PullToRefresh的学习研究(三)---子类们
PullToRefresh的学习研究(三)---子类们
jscoolstar 发表于3年前
PullToRefresh的学习研究(三)---子类们
  • 发表于 3年前
  • 阅读 48
  • 收藏 0
  • 点赞 0
  • 评论 0

标题:腾讯云 新注册用户域名抢购1元起>>>   

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

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就无法拥有这样的展现形式。


共有 人打赏支持
粉丝 0
博文 3
码字总数 6889
×
jscoolstar
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: