美文网首页
Android 改造SwipeRefreshLayout 支持上

Android 改造SwipeRefreshLayout 支持上

作者: 坚持编程_lyz | 来源:发表于2017-03-26 23:11 被阅读59次

    原文链接 : http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650822399&idx=1&sn=9cc9c74d063cc00c6820bdfefc6bf518&chksm=80b78261b7c00b7799577b10a42f598249b02d3bc1d22f281be0391807d103477ccaad9dfc82&mpshare=1&scene=23&srcid=0323qkEeDyK3MOkfXs3LaNYh%23rd

    请支持原文作者 : 鸿洋

    看到这个文章我才想起来,今天推荐一个项目,是我的一位好朋友之前在创业公司的一个项目,后来项目失败了,经允许后将源码分享出来了,该项目也对SwipeRefreshLayout进行了扩展,支持了上拉,如果有实际需求,不妨也试下这个(项目质量非常高)。

    https://github.com/pinguo-sunjianfei/Android-Application-ZJB

    ps:该项目服务端已经停了,所以只能看代码了,运行不起来了~~

    本文作者

    本文由Get_Zoom投稿。
    Get_Zoom的博客地址:
    http://blog.csdn.net/Get_Zoom

    1

    NestedScrolling机制

    之前笔者在设计的时候,想在ViewPager的页面上实现仿微信的左滑删除,但是怎么都实现不了,因为其中跟ViewPager的滑动冲突了,当时才疏学浅(现在也是),进了很多坑,比如滑动的拦截、滑动事件在Down之后会跳过判断等,在没有系统学习过这方面知识的情况下以大败告终。

    所以,谷歌人性化地推出了这个机制,滑动之前和父控件商量一下,一切多么融洽,和之前盲人摸象的方式相比人性化多了。

    (1)滑动流程

    子view获取到点击事件后,询问父亲是否需要配合滑动,然后每一次滑动之前都会询问父亲,并记录下父亲消耗的滑动距离,在上面完成后才进行自己自身的滑动。

    (2)接口

    NestedScrollingChild

    NestedScrollingParent

    (3)帮助类

    NestedScrollingChildHelper NestedScrollingParentHelper

    故名思义,上面的帮助类帮助我们处理了上面父子接口的方法。

    它们帮助我们实现了逻辑上的方法,在一些情况下我们只希望处理子接口或者父接口,为了对接可以在另一个接口使用帮助类(比如下面的实例,改造SwipeRefreshLayout,我们更希望作为父亲处理子view事件而滑动自身,对于上层组件(父)不是很关心,就可以使用NestedScrollingParentHelper来方便编程。

    借用网上的一张图,可以看到两个接口之间的对应关系:

    图片来源:https://segmentfault.com/a/119000000287365

    2

    实例演示:改造SwipeRefreshLayout

    (1)目的
    SwipeRefreshLayout就是一个实现了NestedScrolling机制的控件,可以方便的实现下拉刷新。

    现在我们想加上上拉刷新功能,可以反着做,给下方加一个可拉动的控件(小圆圈),然后处理它的滑动事件。为了能兼顾上层,我们再外面还加了常规的CoordinatorLayout和AppBarLayout作为测试。

    成果:


    (2)准备工作
    改造之前当然要先把人家之前的成果准备好。



    首先当然是把我们的SwipeRefreshLayout移过来,可以换一个名字避免以后的冲突。

    然后布局中要用到两个控件,一个是CircleImageView,也就是显示的小圆圈,附带阴影功能;一个是MaterialProgressDrawable,用于在CircleImageView显示进程(颜色滑动)。

    在移动的时候SwipeRefreshLayout会报错,报错时把东西移动过来就行了。
    然后阅读源码,我们暂时只处理NestedScrolling机制,所以一般的移动流程比如onTouchEvent可以先放着,以后为了和其他不带NestedScrolling控件兼容的时候再改进。

    (3)开始改造工作
    **1.参数测量 **
    一个主要的问题就是,我们下面的圆圈(加载圈,以下简称圆圈)要放在哪?

    原生的直接放在中间然后上去一个圆圈身位的地方,所以下面圆圈水平位置一样,竖直的话就放在屏幕下方。

    综合测试出这样的距离比较好:

    所以相应的位置放置我们就这样:

    2.作为父控件配合滑动


    a.是否配合滑动

    这里我们只增加了一个上拉刷新标志位

    这里也是,只是增加了mTotalUnconsumedBottom ,这是我们上拉刷新的未消费路程。

    b.滑动之前

    我们可以看到源码中的onNestedPreScroll有这么一段处理:

    在滑动前先判断,我们未消费滑动路程是否还有,有则判断方向,如果是滑动的反方向,也就是我们再下拉刷新一半的时候又往回拉,这时做出处理,选择消费当前滑动路程。

    所以我们可以写出下方的拖动预处理:

    这里有个坑要提醒下,一开始笔者自作聪明,觉得consumed参数应该传绝对值,导致后来往回滑的时候子控件跑得飞快(可以想想为什么),所以这里消费了负的路程就传回负的路程,可以看看源码中NestedScrollingChildHelper的实现。

    c.正式滑动

    这个反而比较容易,只需要加上判断当前子控件还能不能往上滑。

    滑动处理:

    大概解释一下,我们的滑动时分段的,在mTotalDragDistance滑动之前是线性的,在这之后会做一个加速的处理,最多延伸一个mSpinnerOffsetEnd
    在实际的view位置改变中,我们使用的是
    setTargetOffsetTopAndBottomForBottom (targetY-mCurrentTargetOffsetBottom, true);

    这个方法,里面是采用
    ViewCompat.offsetTopAndBottom

    来改变view的位置的。

    d.结束滑动

    如果手指离开的时候,拖动距离不为零,那么我们要做判断,做出相应的处理

    可以看到主要有两种处理,以mTotalDragDistance为界限,超过这个滑动距离我们就显示刷新,没有的话就动画回到原点。

    **3.作为子控件配合滑动 **
    我们知道,AppBarLayout和CoordinatorLayout会配合滑动,子view往上滑的时候会隐藏,如果不做处理,在下端圆圈滑动到一半的时候往回滑会把AppBar又拖出来,消费滑动事件,所以我们选择拦截,在下部圆圈滑动的时候优先处理滑动:

    到这里,我们的控件就基本完成了,当然谷歌出版的控件,动画效果是不能少的,它的美观也体现在这里,由于基本是能模仿的,所以这里不再多讲。这个控件的改造主要麻烦在它的动画衔接以及滑动处理机制(加速等),剩下的都很好理解,建议大家动手试一试。

    项目地址:
    https://github.com/SGZoom/DailyWidget/tree/master/widgetpro

    文章跟代码可能包含很多不足之处,欢迎大家帮忙指出错误与不足,谢谢~

    参考文章:
    https://segmentfault.com/a/1190000002873657

    http://blog.csdn.net/al4fun/article/details/53888990

    相关文章

      网友评论

          本文标题:Android 改造SwipeRefreshLayout 支持上

          本文链接:https://www.haomeiwen.com/subject/fautottx.html