文档章节

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

j
 jscoolstar
发布于 2015/06/17 16:21
字数 2029
阅读 48
收藏 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
海淀
程序员
智能卡开发的相关总结

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
java EnumSet学习

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

undefined可以吗
01/13
0
0
腾讯 AI Lab 主任张潼博士:机器学习里的优化问题

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

思颖
01/10
0
0
荐会 | CoRL:机器人与机器学习领域的下一个顶级会议

作为当前炙手可热的研究领域,人工智能的发展可以用“日新月异”来形容。与此相对应的是,尽管目前已经有着诸多人工智能相关的学术会议,但这些学术会议或许过于大而全和不能很好体现出这一领...

岑大师
2017/11/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

70.shell的函数 数组 告警系统需求分析

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析 20.16/20.17 shell中的函数: ~1. 函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段...

王鑫linux
今天
2
0
分布式框架spring-session实现session一致性使用问题

前言:项目中使用到spring-session来缓存用户信息,保证服务之间session一致性,但是获取session信息为什么不能再服务层获取? 一、spring-session实现session一致性方式 用户每一次请求都会...

WALK_MAN
今天
5
0
C++ yield()与sleep_for()

C++11 标准库提供了yield()和sleep_for()两个方法。 (1)std::this_thread::yield(): 线程调用该方法时,主动让出CPU,并且不参与CPU的本次调度,从而让其他线程有机会运行。在后续的调度周...

yepanl
今天
4
0
Java并发编程实战(chapter_3)(线程池ThreadPoolExecutor源码分析)

这个系列一直没再写,很多原因,中间经历了换工作,熟悉项目,熟悉新团队等等一系列的事情。并发课题对于Java来说是一个又重要又难的一大块,除非气定神闲、精力满满,否则我本身是不敢随便写...

心中的理想乡
今天
34
0
shell学习之获取用户的输入命令read

在运行脚本的时候,命令行参数是可以传入参数,还有就是在脚本运行过程中需要用户输入参数,比如你想要在脚本运行时问个问题,并等待运行脚本的人来回答。bash shell为此提 供了read命令。 ...

woshixin
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部