文档章节

PullToRefresh的学习研究(二)

j
 jscoolstar
发布于 2015/06/16 18:39
字数 2250
阅读 26
收藏 0
点赞 0
评论 0

注意到里面好多类似这样的方法public void setReleaseLabel(CharSequence releaseLabel, Mode mode) {
        getLoadingLayoutProxy(mode.showHeaderLoadingLayout(),
                mode.showFooterLoadingLayout()).setReleaseLabel(releaseLabel);
    },这些都是ILoadingLayout这个接口的方法,看来以前代码设计者是把状态改变时的lable改变写在了基类里,然后子类直接调用方法来改变的。但是现在应该没有什么用了,因为headlayout是继承的LoadingLayout,而LoadingLayout实现了IloadingLayout接口。只需要在自定义的LoadingLayout里实现方法就可以了,基类会在适当的时机调用headlayout.setxxxlabel方法,而不是调用自己的setxxxLable了。全部删除后demo中只有一个ListAct有错误mPullRefreshListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
            @Override
            public void onRefresh(PullToRefreshBase<ListView> refreshView) {
                String label = DateUtils.formatDateTime(getApplicationContext(), System.currentTimeMillis(),
                        DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);

                // Update the LastUpdatedLabel
//                refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(label);
                refreshView.getHeaderLayout().setLastUpdatedLabel(label);
                // Do work to refresh the list here.
                new GetDataTask().execute();
            }
        });

    他在回调中还是使用的refreshView.getLoadingLayoutProxy().这里建议将基类原来的getHeaderLayout()设置为public,这样也为自定义的LoadingLayout做准备,也可以封装一部分常用的属性在基类中,比如setLastUpdatedLabel(label){内部调用headlayout去处理}其实LoadingLayout和基类之间的关系还是有点“深”,后面尝试分离一下,否则这样虽然有 一定灵活度,但其实还是定死了几个东西,比如你即使自定义,也必须有一堆很必须的值,比如updateText,可能有些时候你并不需要它,demo中在不需要的时候,其实只是没有设置text,所以就看不到。但不代表控件本身不存在。我觉得可以在LoadingLayout中只实现state周期必须的几个东西,然后在子类中去设置文本之类的操作,嗯,这些读者们自行考虑吧,其实感觉最重要的是接下来要看的ontouch事件,以及各个子类对临界值的判断。如此则可以写出更多灵活的代码,比如有些app,下拉的时候,从上面出来个发条,但是listview本身并不动,这样的情况使用博文介绍的组件是不能实现的,当然也许可以通过变动来实现,比如上篇说了,是通过padding定位header,然后通过layout自己的scrollto属性来呈现下拉的。那么问题来了,挖掘技术哪家强?。。我去,是想实现listview不动的情况应该怎么办?学会了这里的逻辑,完全可以继承一个RelativeLayout了,或者尝试改变lsitview和hear之间的margain试试?(但线性布局,它会盖着header。。。)感觉应该使用RelativeLayout,这样感觉好一点,方便操控,学着学着就想推倒了。言归正传,先把核心学到手,后面随意优化(其实也不难,使用layout(int top,int left...)来替换掉scrollto就可以了,scrollto在这里其实占了个大便宜而已,带来的劣势也看到了,不方便重叠布局Head)。

大家自行复习  onInterceptTouchEvent 和onTouch吧,或者以后我会补一篇相关文章。总结就是onInterceptTouchEvent从父类向子类传递,遇到true则停止并交由当时的子类来执行onTouch,ontouch开始反传,遇true则自己消耗掉事件及以后的事件。

@Override
    public final boolean onInterceptTouchEvent(MotionEvent event) {

        if (!isPullToRefreshEnabled()) {
            return false;// 如果设置为不能fresh,则不拦截,交给子view处理,即所有touch事件交给了listview,上下的headlayout等也一直invisiable
        }

        final int action = event.getAction();

        if (action == MotionEvent.ACTION_CANCEL
                || action == MotionEvent.ACTION_UP) {
            mIsBeingDragged = false;
            return false;
        }

        // 动作不是按下,不是松手(差不多也就剩下move了)并且当前在拖动状态,则拦截给自己的ontouch处理
        if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {
            return true;//这里就会跳转到自己的ontouch,同时所有的子view都不再可能接收ontouch事件了
        }

        // mIsBeingDragged默认是false的,所以,当第一次move并且未将mIsBeingDragged设置true时,就会执行这里

        switch (action) {
        case MotionEvent.ACTION_MOVE: {
            // If we're refreshing, and the flag is set. Eat all MOVE events
            // 如何设置了 刷新中不能滑动,并且当前在刷新中,则拦截处理,这样listview就接收不到事件了,自然也就不能滑动了
            if (!mScrollingWhileRefreshingEnabled && isRefreshing()) {
                return true;
            }

            if (isReadyForPull()) {
                final float y = event.getY(), x = event.getX();
                final float diff, oppositeDiff, absDiff;

                // We need to use the correct values, based on scroll
                // direction
                switch (getPullToRefreshScrollDirection()) {
                case HORIZONTAL:
                    diff = x - mLastMotionX;
                    oppositeDiff = y - mLastMotionY;
                    break;
                case VERTICAL:
                default:
                    diff = y - mLastMotionY;
                    oppositeDiff = x - mLastMotionX;
                    break;
                }
                absDiff = Math.abs(diff);

                // 移动距离超过了判断为滑动的最小距离mtouchslop..并且(按纵向分析)(纵向的移动距离大于横向 ||
                // !mFilterTouchEvents)
                if (absDiff > mTouchSlop
                        && (!mFilterTouchEvents || absDiff > Math
                                .abs(oppositeDiff))) {
                    if (mMode.showHeaderLoadingLayout() && diff >= 1f
                            && isReadyForPullStart()) {// 如果当前可以显示header(其实就是看mModel是可以下拉刷新或者上下都可以拉的情况),并且移动差距>1f(向下拉动),并且子类判断已经准备好可以开始下拉了(比如listivew的话第一个item已经到头了)//这里重点就两个,一是分辨出当前是在向上还是向下做运动,二是子类要知道现在是否到顶或底了
                        mLastMotionY = y;
                        mLastMotionX = x;
                        mIsBeingDragged = true;
                        if (mMode == Mode.BOTH) {
                            mCurrentMode = Mode.PULL_FROM_START;
                        }
                    } else if (mMode.showFooterLoadingLayout() && diff <= -1f
                            && isReadyForPullEnd()) {
                        mLastMotionY = y;
                        mLastMotionX = x;
                        mIsBeingDragged = true;
                        if (mMode == Mode.BOTH) {
                            mCurrentMode = Mode.PULL_FROM_END;
                        }
                    }
                }
            }
            break;
        }
        case MotionEvent.ACTION_DOWN: {
            if (isReadyForPull()) {
                mLastMotionY = mInitialMotionY = event.getY();
                mLastMotionX = mInitialMotionX = event.getX();
                mIsBeingDragged = false;
            }
            break;
        }
        }

        return mIsBeingDragged;
    }


@Override
    public final boolean onTouchEvent(MotionEvent event) {

        if (!isPullToRefreshEnabled()) {
            return false;
        }

        // If we're refreshing, and the flag is set. Eat the event
        if (!mScrollingWhileRefreshingEnabled && isRefreshing()) {
            return true;
        }

        if (event.getAction() == MotionEvent.ACTION_DOWN
                && event.getEdgeFlags() != 0) {
            //getEdgeFlags():当事件类型是ActionDown时可以通过此方法获得,手指触控开始的边界. 如果是的话,有如下几种值:EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM
            return false;
        }

        switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE: {
            if (mIsBeingDragged) {
                mLastMotionY = event.getY();
                mLastMotionX = event.getX();
                pullEvent();
                return true;
            }
            break;
        }

        case MotionEvent.ACTION_DOWN: {
            if (isReadyForPull()) {
                mLastMotionY = mInitialMotionY = event.getY();
                mLastMotionX = mInitialMotionX = event.getX();
                return true;
            }
            break;
        }

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP: {
            if (mIsBeingDragged) {
                mIsBeingDragged = false;

                if (mState == State.RELEASE_TO_REFRESH
                        && (null != mOnRefreshListener || null != mOnRefreshListener2)) {
                    setState(State.REFRESHING, true);
                    return true;
                }

                // If we're already refreshing, just scroll back to the top
                if (isRefreshing()) {
                    smoothScrollTo(0);
                    return true;
                }

                // If we haven't returned by here, then we're not in a state
                // to pull, so just reset
                setState(State.RESET);

                return true;
            }
            break;
        }
        }

        return false;
    }

ontouch里面最重要的两个个方法就是:(擦,粘两个方法的代码就超出字数限制了)

1、//基本就是按滑动的位置来改变状态,不同的state也会在LoadingLayout里有相关的state设置,比如protected void onPullToRefresh() {
        switch (mCurrentMode) {
        case PULL_FROM_END:
            mFooterLayout.pullToRefresh();
            break;
        case PULL_FROM_START:
            mHeaderLayout.pullToRefresh();
            break;
        default:
            // NO-OP
            break;
        }
    }

在调用这个方法之前的move里面会调用onpullevent(),里面会调用 mFooterLayout.onPull(scale);这个是把当前的拖动百分比给Loadinglayout,这样就可以根据百分比显示旋转或翻转的动画了。onpullevent里面有个注意点,它是根据当前拖拽的距离和Loadinglayout的实际内容距离做的比较,它有个innerLayout,我们知道LoadingLayout有listview的0.6倍,而header的实际大小是xml定义的,而且他放在了LoadingLayout的底部(foot反之),根据这样来显示“向下拉动刷新”和“释放开始刷新”之类的字样提醒。同时会调用setState(State.PULL_TO_REFRESH);setState(State.RELEASE_TO_REFRESH);,当然字样提醒就是在对应的onReleaseToRefresh事件里,去调用mHeaderLayout.releaseTorefresh去实现的。(其实这里就是另一个方法了:onpullevent,不过贴代码就超了)

final void setState(State state, final boolean... params) {
        mState = state;
        if (DEBUG) {
            Log.d(LOG_TAG, "State: " + mState.name());
        }

        switch (mState) {
        case RESET:
            onReset();
            break;
        case PULL_TO_REFRESH:
            onPullToRefresh();
            break;
        case RELEASE_TO_REFRESH:
            onReleaseToRefresh();
            break;
        case REFRESHING:
        case MANUAL_REFRESHING:
            onRefreshing(params[0]);
            break;
        case OVERSCROLLING:
            // NO-OP
            break;
        }

        // Call OnPullEventListener
        if (null != mOnPullEventListener) {
            mOnPullEventListener.onPullEvent(this, mState, mCurrentMode);
        }
    }

ps:其实分离Loadinglayout还是挺容易的,因为现在LoadingLayout,它管的事有点多,他管的事就是有相同布局风格的代表,比如都有updatelabel,都有mHeaderImage等等。其实他应该还有个父类,或者或他应该去掉多余的方法,再拥有个子类(因为fresh的base基类里面的headLayout和footLayout都是LoadingLayout类型,所以不适合再做父类,或者做了父类后就要把基类的head foot的对应类型改成父类),比如叫做 standerLoadinLayout(标准型Loading),然后Rotato和Flip两个都继承stantder,stander中,可以做一些原来的LoadingLayout的事情,比如拥有mHeaderText控件,在reset中可以处理settext等。我们需要自定义的时候,就可以继承简化的LoadingLayout,来做一个非常随意的独特布局,比如一个animations的帧动画。(比如下拉过程中,小人在走,松手后,小人开始跑步。比如下拉的时候火箭开始点火,松手就开始飞,加载完就飞出屏幕了等等)

到这里,基类基本就看完了,其实边写边看,感觉印象很深,写着写着也容易停下来思考问题,下边就开始看各个子类了,大体看了下,都非常简单,因为父类做了不少事情,子类只是提供了不同的临界判断标准而已。再有基类的方法有onSaveInstanceState,存储状态就不讲了,他自己存完必须的状态后,会调用子类的ab方法onPtrsave,方便不通的子类执行不通的存储,比如Listview可能希望存储当前是第几个index。webview更希望存储当前加载的哪个url。:)

© 著作权归作者所有

共有 人打赏支持
j
粉丝 0
博文 3
码字总数 6889
作品 0
海淀
程序员
智能卡开发的相关总结

1.EMV技术学习和研究(一)开篇(http://blog.csdn.net/xuture/article/details/9208259) 2.EMV技术学习和研究(二)应用选择(http://blog.csdn.net/xuture/article/details/9250067) 3.EMV技......

IT追寻者 ⋅ 2016/09/08 ⋅ 0

学习东西总结:

一.JAVA 基础 1、JAVA并发编程 2.JAVA NIO系列 3.JVM深入了解 4.JAVA性能优化相关研究 5.JAVA7,8新特性 二、数据库 1.数据库优化研究 2.MYSQL高可用性研究 3.MYSQL源码研究 三、网络 1.HTTP...

QH_C ⋅ 2016/03/25 ⋅ 0

Android-PullToRefresh使用

接上篇,很多人看到有好源码,但是在使用时碰到了问题。在此简单介绍一下,希望能够对那些不会的童鞋们有所帮助。 首先下载源码,源码地址:https://github.com/chrisbanes/Android-PullToR...

崔同亮 ⋅ 2013/10/23 ⋅ 0

步入研二,迷茫中,搞底层框架研究(或者linux内核)还是做上层应用前途哪个好呢!?

本人现已步入研二,想抓紧再学一些新技术,不知道往什么方向啊? 我研究生的方向是,移动终端的性能和能耗的评测。现在对android的整体框架已有点了解,但是要全部搞懂感觉压力好大;对linux...

wangxigui ⋅ 2013/09/23 ⋅ 11

中科院孙冰杰博士:基于网络化数据表示学习的重叠社区发现研究 | 分享总结

雷锋网AI科技评论按:网络是大数据的重要组织形式,然而网络化的数据由于缺少高效可用的节点表示,而难于直接应用。网络化数据表示学习通过将高维稀疏难于应用的数据转化为低维紧凑易于应用的...

杨文 ⋅ 2017/12/20 ⋅ 0

计算机视觉与图像处理、模式识别、机器学习学科之间的关系

在我的理解里,要实现计算机视觉必须有图像处理的帮助,而图像处理倚仗与模式识别的有效运用,而模式识别是人工智能领域的一个重要分支,人工智能与机器学习密不可分。纵观一切关系,发现计算...

小金子 ⋅ 2014/07/07 ⋅ 0

程序员,如何做到持续学习

我其实是一个悲观主义者,从开始成为一名程序员的那一天开始,我就对自己的职业充满着担忧。早期,我担忧的是我刚进入这一行,落后身边从事这一行多年的人太多,跟他们比,我一开始就处于“不...

蓝狐乐队 ⋅ 2014/06/19 ⋅ 2

腾讯 AI Lab 主任张潼博士:机器学习里的优化问题

雷锋网 AI 科技评论按,日前,在由上海财经大学交叉科学研究院(RIIS)主办,杉数科技有限公司协办的「现代运筹学发展讨论会」上,腾讯 AI Lab(腾讯人工智能实验室)主任张潼博士发表了精彩...

思颖 ⋅ 01/10 ⋅ 0

这些人你还不认识?!一文带你有姿势地侃深度学习大佬

大数据文摘作品 编译:余志文,笪洁琼,钱天培 近几年间,深度学习的兴起造就了一批超级巨星。一向在学术界默默无闻的大佬们,相继成为了业界的领头人,而他们的声名也再从业界一路传至大众耳...

uwr44uouqcnsuqb60zk2 ⋅ 2017/11/03 ⋅ 0

【政策】北京市科委发布最新征集新一代人工智能、脑认知与类脑技术等六大领域储备课题

去年,在国家层面频频出台一系列人工智能发展规划政策后,2018年地方进入政策落地实施阶段。 11日,北京市科委发布六份通知,征集2018年六大技术领域储备课题,这六大领域分别为: ①认知与类...

技术小能手 ⋅ 01/12 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

oAuth2 升级Spring Cloud Finchley.RELEASE踩坑分享

背景 6.19号,spring团队发布了期待已久的 Spring Cloud Finchley.RELEASE 版本。 重要变化: 基于Spring Boot 2.0.X 不兼容 Spring Boot 1.5.X 期间踩过几个坑,分享出来给大伙,主要是关于...

冷冷gg ⋅ 33分钟前 ⋅ 0

OSChina 周一乱弹 —— 理发师小姐姐的魔法

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @冰冰棒- :分享田馥甄的单曲《My Love》 《My Love》- 田馥甄 手机党少年们想听歌,请使劲儿戳(这里) @Li-Wang :哎,头发又长了。。。又要...

小小编辑 ⋅ 58分钟前 ⋅ 4

Kafka1.0.X_消费者API详解2

偏移量由消费者管理 kafka Consumer Api还提供了自己存储offset的功能,将offset和data做到原子性,可以让消费具有Exactly Once 的语义,比kafka默认的At-least Once更强大 消费者从指定分区...

特拉仔 ⋅ 今天 ⋅ 0

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(十一)JavaScript的DOM操作

JavaScript零基础入门——(十一)JavaScript的DOM操作 大家好,欢迎回到我们的JavaScript零基础入门。最近有些同学问我说,我讲的的比书上的精简不少。其实呢,我主要讲的是我在开发中经常会...

JandenMa ⋅ 今天 ⋅ 0

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 今天 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 今天 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 今天 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部