文档章节

PullToRefresh的学习研究(三)---子类们

j
 jscoolstar
发布于 2015/06/17 16:21
字数 2029
阅读 49
收藏 0

子类有多个,先从最常用最关注的说起吧。

1、public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extends PullToRefreshBase<T>

首先有这么一个成员变量:/**
     * TODO 提示器,比如滑动顶部的时候渐显出来,告诉用户这个位置可以下拉刷新了
     * @Auther : shenqichao
     * @Date:2015年6月17日 上午11:14:27
     */
    private IndicatorLayout mIndicatorIvTop;
    private IndicatorLayout mIndicatorIvBottom;

private OnScrollListener mOnScrollListener;这里定义了一个滑动监听,这其实是供给用户处理滑动事件的,它本身不处理刷新相关的逻辑,因为在构造里面有这么一句:public PullToRefreshAdapterViewBase(Context context) {
        super(context);
        mRefreshableView.setOnScrollListener(this);
    }

自己的refreshableView的滑动监听其实是子类自己,而在对应的各个接口函数里都会调用mOnScrollListener.do,比如:public final void onScrollStateChanged(final AbsListView view, final int state) {
        /**
         * Check that the scrolling has stopped, and that the last item is
         * visible.
         */
        if (state == OnScrollListener.SCROLL_STATE_IDLE && null != mOnLastItemVisibleListener && mLastItemVisible) {
            mOnLastItemVisibleListener.onLastItemVisible();
        }

        if (null != mOnScrollListener) {
            mOnScrollListener.onScrollStateChanged(view, state);
        }
    }

下面是子类核心功能作用,(指示器只是添花的作用,不要也不影响)

protected boolean isReadyForPullStart() {
        return isFirstItemVisible();
    }

    protected boolean isReadyForPullEnd() {
        return isLastItemVisible();
    }

先看第一个,是否准备好顶部下拉刷新了?return的是isFirstItemVisible();,虽然名字是这样起的,但是其方法内部并不是判断的仅仅是是否visiable。

private boolean isFirstItemVisible() {
        final Adapter adapter = mRefreshableView.getAdapter();

        if (null == adapter || adapter.isEmpty()) {
            if (DEBUG) {
                Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");
            }
            return true;

        } else {

            /**
             * This check should really just be:
             * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
             * internally use a HeaderView which messes the positions up. For
             * now we'll just add one to account for it and rely on the inner
             * condition which checks getTop().
             */
            if (mRefreshableView.getFirstVisiblePosition() <= 1) {
                final View firstVisibleChild = mRefreshableView.getChildAt(0);
                if (firstVisibleChild != null) {
                    return firstVisibleChild.getTop() >= mRefreshableView.getTop();
                }
            }
        }

        return false;
    }

代码解决了第一篇的一个疑问,即listview加了自己header之后是否还可用。这里可以看到代码是可用的。首先 if (mRefreshableView.getFirstVisiblePosition() <= 1) {感觉这里的代码有点累赘了,可能是sdk版本的问题?这里其实确实可以只用getFirstVisiblePosition()==0来判断的,在==0的时候,在获取getChildAt(0),去获取他的getTop和listview本身的gettop对比),写到这里的时候卡壳了,我研究了很久为什么作者要写成<=1,我自己做了个实验,用了个普通的listview,自己加了个header,有header的时候,就显示Header是0,没有就第一个元素是0,所以不管怎样我都觉得滑动要判断第0个,所以觉得作者不用写成<=1。但是我运行demo的代码,有header的时候getFirstVisiblePosition()=1,没header的时候也显示1,整的我特别的莫名其妙.由于马虎看了好久代码也没找到原因,后来~~~我终于明白了,什么是哎。。

PullToRefreshListView继承adpterview,

@Override
    protected void handleStyledAttributes(TypedArray a) {
        super.handleStyledAttributes(a);

        mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true);

        if (mListViewExtrasEnabled) {
            final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL);

            // Create Loading Views ready for use later
            FrameLayout frame = new FrameLayout(getContext());
            mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a);
            mHeaderLoadingView.setVisibility(View.GONE);
            frame.addView(mHeaderLoadingView, lp);
            mRefreshableView.addHeaderView(frame, null, false);

            mLvFooterLoadingFrame = new FrameLayout(getContext());
            mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a);
            mFooterLoadingView.setVisibility(View.GONE);
            mLvFooterLoadingFrame.addView(mFooterLoadingView, lp);

            /**
             * If the value for Scrolling While Refreshing hasn't been
             * explicitly set via XML, enable Scrolling While Refreshing.
             */
            if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
                setScrollingWhileRefreshingEnabled(true);
            }
        }
    }这里是基类留给所有子类来处理自己的attr的, mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true);这行代码很长。。在写博客,并且要在模拟器上测试,所以eclipse不是最大化,这行代码没显示全,我理解的意思是listview是否可以扩展,即分组。所以认为取这属性时默认应该是false的。所以也就不会执行false里面的东西。。。但是我错了,小裤裤都错掉了。这个if里面加了mHeaderLoadingView,是真正意义上的加了。。。但是还设置成了visiable=gone,然后就出现了怪现象,第零个item总打印成他是第一个。然后我继续围绕代码和运行时的表现,发现mListViewExtrasEnabled这个字段不是代表分组的情况。而是当freshing的时候,listview是否可以滑动。当我实验完这个字段之后我又记起基类里有这个字段mScrollingWhileRefreshingEnabled,我就在想他们俩不是一个意思吗?然后又开始换状态运行发现了一个问题。mScrollingWhileRefreshingEnabled这个确实也是代表freshing的时候view是否可滑动。如果是false,那刷新的时候在基类的touch拦截那里就拦截了,所以也就无法滑动freshableview了。如果设置成true,就可以滑动,但是lsitview的体验是,他自己可以滑动,但是上面的head加载条却一直显示着,因为继承的LinearLayout,而且代码发现mScrollingWhileRefreshingEnabled这个是true的时候,在touch事件里面并没有处理scrollto来改变listview和header的滑动关系,比如代码处理的原理就是header位置不变,显示刷新中的状态,listview在“header”的下面可以上下滑动,说白了就是listview没有全屏,在下面的区域展示着自己。如果想做复杂点,我觉得应该在touch里面scrollto来改变header的位置,当达到临界值时,再不拦截touch,再交给freshableview去执行,这样就能实现listview和加载的header同时上移的视觉。mListViewExtrasEnabled这个属性,其实也是代表freshing的时候是否可以滑动。但是它作为一个单独出来的变量,仅仅是为了Listview自己的方便,这个属性默认为true,true的时候,会add一个真正的header,然后gone掉,当freshing的时候,他会把基类的headlayout隐藏掉,然后显示自己的header,并调用header的.freshing方法。当fresh完成,它再gone掉,然后显示基类的loadinglayout。。我觉得需要优化。抱着试试看的态度,我把gridview的demo设置成了刷新时可滑动属性,嗯,不好看。因为gridview不能加header。所以只能是第一种表现形式,而且发现一个UIbug:demo中是空的gridview,下拉刷行过程中,原来是不能滑动的,设置成可以滑动之后,因为gridview的是空的,lastvisiableitem自然是空的,所以你刚刚执行了下拉刷新后,马上往上提,底部会出现加载更多的footer,当然作者的代码逻辑只会让UI显示出来,却不会加载更多。但我觉得,加载更多也不该显示,同理,当加载更多的时候,也不应该下拉显示刷新的按钮,都应该等fresh结束之后,再去决定用户的操作是想下拉还是上拉。

好了,基本到这里了,listview竟然还是所有子类里面最复杂的一个。其他的几个都可以根据各自的特色来实现基类的abstract方法。比如webview,可以根据自己的contentheight属性(当然查了下api只有这个,没有contentwidth属性,也就意味着webview是不能左拉刷新的。。。)scollview就是根据getScrollY来判断。总之就是实现基类的@Override
    protected boolean isReadyForPullStart()
    protected boolean isReadyForPullEnd()

这两个方法,你甚至可以把方法内部写成滑动一半就刷新,只要你的子类告诉基类,我现在处于ready状态,基类再结合其他属性比如当前是“向上”还是“向下”滑动?等来决定现在要不要显示出LoadingLayout.

另外就是几个子类都根据api级别来构建listview/webview等等。因为api大于9的都有一个overScroll方法,通过OverScrollHelper来重新这个方法以达到更好的过量滑动视觉效果,如果api没有大于9,是无所谓了。


后记:listview里面有这样一句if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
                setScrollingWhileRefreshingEnabled(true);
            },当mListViewExtrasEnabled为true时,它会找xml配置,如果不存在那个属性配置就配置为true,这样mListViewExtrasEnabled才能生效,否则即使mListViewExtrasEnabled是true,如果xml明确配置ptrScrollingWhileRefreshingEnabled为false,那么也无法在freshing的时候滑动。看看能否优化成不使用mListViewExtrasEnabled,理论上所有的UI当下拉更新时,如果可以滑动,都应该带着顶部的loading一起滑动,不能因为只有listview有header所以有这样好的表现形式,而其他几个view就无法拥有这样的展现形式。


© 著作权归作者所有

共有 人打赏支持
j
粉丝 0
博文 3
码字总数 6889
作品 0
海淀
程序员
私信 提问
java EnumSet学习

一、EnumSet 简单介绍 二、EnumSet的内部设计思路 EnumSet是一个抽象类,内部多处采用静态工厂方法。它不对外提供构造函数,只能通过一系列静态方法,如of(...)、noneOf(...)、copyOf(...)、...

undefined可以吗
01/13
0
0
Android-PullToRefresh使用

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

崔同亮
2013/10/23
0
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
4
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
5
0
Android SDK示例代码学习(1)----BouncingBalls

最近在学习android的开发,打算把sdk的示例代码研究一下,一直以来都没有做笔记的习惯,以至于看过的东西记住的少遗忘的多,因此试试记下笔记,以备以后查询。 ----------------------------...

开开904
2014/03/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS 安装PHP5和PHP7

安装PHP5 下载解压二进制包 [root@test-a src]# cd /usr/local/src/[root@test-a src]# wget http://cn2.php.net/distributions/php-5.6.32.tar.bz2[root@test-a src]# tar jxvf php-5.6......

野雪球
今天
3
0
windows上类似dnsmasq的软件Dual DHCP DNS Server

官网地址:http://dhcp-dns-server.sourceforge.net/官网定向的下载地址:https://sourceforge.net/projects/dhcp-dns-server/files/ 设置参考地址:http://blog.51cto.com/zhukeqiang/18264......

xueyuse0012
今天
3
0
LinkedHashMap源码解析

前言 HashMap中的元素时无序的,也就是说遍历HashMap的时候,顺序和放入的顺序是不一样的。 如果需要有序的Map,就可以采用LinkedHashMap. LinkedHashMap通过维护一个包含所有元素的双向链表,...

grace_233
今天
3
0
初识flask

文档 0.10.1版本 http://www.pythondoc.com/flask/index.html 1.0.2版本 https://dormousehole.readthedocs.io/en/latest/ 安装flask $ pip3 install flaskCollecting flask Downloading......

yimingkeji
昨天
5
0
Akka系统《sixteen》译

Actor是一个封装状态(state)和行为(behavior)的对象,它们只通过交换消息通信(放入收件人邮箱的邮件)。从某种意义上说,Actor是最严格的面向对象编程形式,但它更适合将他们视为人:在与Act...

woshixin
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部