Android自己动手实现下拉刷新控件(2)—-知识储备

Android自己动手实现下拉刷新控件(2)—-知识储备

整个系列文章的脉络是:

在上一篇文章分析对比了当前流行的两类风格的刷新控件,无论我们准备实现那一种风格的控件,都需要做知识的储备。本篇主要分析动手实现下拉控件前,我们应该有哪些知识储备。

github地址:https://github.com/BigPig-LittleTail/RefreshLayout
ps: 自己看文章和github开源库的时候最烦的就是没有readme和图的文章,不料自己也是其中一员,后续可能会补上动图。这是后续加上的效果图,readme还没有写。有加载进度条的头部的图片怎么也上传不上去。先拿这个没有进度条的凑合着吧。


实现的RefreshLayout继承自什么?

对于这个问题,我不加思索的就选择了ViewGroup,但什么选择ViewGroup而不是View,显然回答SwipeRefreshLayout是继承自ViewGroup所以我也选择ViewGroup是不合格的,所以要清楚ViewGroup和View的区别。

对ViewGroup在安卓开发网站的介绍翻译:ViewGroup是一种特殊的视图,可以包含其他视图(称为子视图)。视图组是布局和视图容器的基类。这个类还定义了ViewGroup.LayoutParams类作为布局参数的基类。

我要实现的RefreshLayout要包含一个View作为子视图,从而实现刷新功能与子视图功能的隔离。所以应该选择ViewGroup作为RefreshLayout的父类。


RefreshLayout的测量和布局

对于测量和布局的原理,我参考了之前读到过的文章https://www.jianshu.com/p/5a71014e7b1b

以我自己的理解来总结:View和ViewGroup的测量是递归进行的,先对子View进行测量,根据测量结果和Mode来决定View和ViewGroup的参数。

RefreshLayout传递给子view的测量mode是Exactly,就表示无论子view想要多大的空间,它都不会超过RefreshLayout的尺寸。
在onMeasure中测量了、header的尺寸。
在onLayout中,调用子view和haeder的layout方法将他们布局在正确的位置。header布局在0坐标之上,布局在中间位置。


事件分发

一个事件包含

  • ACTION_DOWN
  • ACTION_MOVE
  • ACTION_UP
  • ACTION_POINTER_DOWN
  • ACTION_POINTER_UP等

事件分发的机制参考https://blog.csdn.net/salmon_zhang/article/details/76746159

但仍然有一个分非常大的疑问困扰我,swiperefreshlayout为什么不重写dispatchTouchEvent方法?
我通过阅读viewgroup的源码有了自己的初步答案。

viewgroup中的dispatchTouchEvent完成了以下的任务:

  • 1.对ACTION_DOWN进行处理,主要是清除以前的触摸事件,重置参数。
  • 2.检查是否拦截(只有ACTION_DOWN才会触发这段代码)
  • 3.检查cancel
  • 4.事件分发

    所以分析我们要完成的refreshlayout,我们只要在2过程检查是否拦截事件,即调用onInterceptTouchEvent的时候进行正确的拦截,就能够将事件正确的分发。

开发后对上述做一些补充(没兴趣的可以不看,斜体字):
上述初步答案真的是初步答案,在我完成整个开发和文档之后,我想实现—-无缝下拉刷新,就是指先向上滑,内容视图RecyclerView向上滚动,再向下拉,向下拉的过程实现可以不用重新抬起手指,就可以拉出下拉刷新框。

我经过分析和尝试,得出了两种解决方案,一种是SwipeRefreshLayout实现了NestedScrollingParent接口,嵌套滑动,因为嵌套滑动我掌握的不是很深刻,简单的阅读了一下文章,初步的理解是,嵌套滑动在事件分发给子View之前,又给了一次父控件处理滑动的机会,这套机制不是传统的事件分发,我打了Log,传统的事件分发onInterceptTouchEvent和onTouchEvent都没有被调用。我要实现约定的效果,一种思路也是实现NestedScrollingParent接口;第二种思路就是,重写ViewGroup的dispatchTouchEvent,来进行“手动分发”事件。

对于手动分发这一点,因为viewgroup的dispatchTouchEvent在一次ACTION_DOWN之后,如果被拦截,那么之后的事件全部由ViewGroup处理;没有被拦截,会在子View调用禁止拦截之前还有几次调用ViewGroup的onInterceptTouchEvent机会。 所以我们分析之前的需求,无缝下拉刷新,如果不完全重写一套dispatchTouchEvent方案,在已经交由ViewGroup处理后的事件,必须用ACTION_DOWN打断,这样就相当于有了一次用户本不想要的ACTION_DOWN事件,所以最终选择的思路是实现NestedScrollingParent接口。


状态转化

下拉刷新过程,一定有很多状态的转化。
所以我画了一个状态机
下拉刷新状态机

可以看到,弧很多都与ACTION_MOVE有关,所以状态机的设计还是比较合理,这样可以隔离开代码和状态的更改。

猜你喜欢

转载自blog.csdn.net/BigPig_LittleTail/article/details/81454031
今日推荐