[TOC]
免责声明: 这篇文章还没有写完,发布的原因是因为我懒的放到草稿箱了,如有错误或者以后请勿怪
RecyclerView介绍
RecyclerView
是Google support-v7包中的控件,用于提供一个列表的显示,和 ListView
类似,但是比 ListView
更高级也更具扩展性,它更倾向于使用一个模块化的方式来使用多个模块共同实现一个复杂的列表控件,RecyclerView
主要由如下几个组件构成
LayoutManager
用于控制List子View的测量和布局Adapter
和ListView
中的Adapter功能类似,但是已经预先添加了ViewHolder
,不需要我们手动添加ItemDecoration
用于控制和显示分割线ItemAnimator
用于实现Item显示消失时动画效果
当然除了上面所说的这些模块之外,RecyclerView
还把很多其他的功能也都拆分了出来,这里就不一一列举,文中遇到了在做说明。
LayoutManager
LayoutManager
相当于把本身View应该完成的测量和布局过程抽离出来单独处理,而这两个步骤也是决定一个View显示效果的重要步骤,因此同一个 RecyclerView
完全可以通过不同的 LayoutManager
实现不同的显示效果,而不是使用不同的控件。
目前Google已经预先提供好了几种 LayoutManager
,分别如下所示
LinearLayoutManager
实现类似ListView
列表样式的布局GridLayoutManager
实现类似GridView
网格样式的布局StaggeredGridLayoutManager
实现了瀑布流样式的布局
我们以 LinearLayoutManager
为例来说明 LayoutManager
在 RecyclerView
中的重要作用,首先先说明一下 LinearLayoutManager
中的两个辅助类,这两个类在 LinearLayoutManager
的工作中也起着一定作用
AnchorInfo
布局的锚点,在测量和布局过程中LinearLayoutManager
都是先确定一个锚点位置,然后根据锚点,分别向上和向下去测量和布局子View
LayoutState
是LinearLayoutManager
在填充整体布局的帮助类,他可以通过一个给定的方向获取下一个需要填充的View
onMeasure
我们都知道控件的展示主要分为测量、布局、绘制等三个阶段进行,我们首先关注 RecyclerView
的测量过程。代码片段会省略部分代码和注释
|
可以看到在 onMeasure
方法中,如果我们给 RecyclerView
设置了不是 Wrap_Content
的宽高,那么 RecyclerView
的测量过程很简单,直接使用父控件给定的宽高即可,只有当我们设置为 Wrap_Content
时,才需要先去测量子 View 。
测量子 View 的过程事实上是在 dispatchLayoutStep2
方法中进行的,这个方法事实上是 Layout 时调用的方法,这个不难理解,因为只有在确定了 Layout 的方式时,才能真正确定子 View 需要多少的屏幕空间
private void dispatchLayoutStep2() { |
dispatchLayoutStep2
主要的功能就是为 mState
的更新了一些 RecyclerView
的最新状态,然后调用了 LayoutManager
的 onLayoutChildren
方法,值得注意的是这个方法和上个方法一样是用于布局的,所以后面还会调用,这里暂时只说明测量的部分。
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { |
上面的代码中可以看出在 onLayoutChildren
过程中,LinearLayoutManager
是首先确定一个锚点,然后从锚点位置开始向不同方向填充布局。真正的填充部分代码在 fill
方法中
int fill(RecyclerView.Recycler recycler, LayoutState layoutState, |
可以看到在 fill
方法中起着比较核心作用的是 layoutChunk
方法
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, |
上面的代码其实很清楚了,layoutChunk
方法首先获取的 ChildView
,对它进行测量,然后布局。恩,你没有看错就是布局 Layout
,通过布局方法确定 ChildView
的具体位置,dispatchLayoutStep2
方法的深入展开到此结束,让我们回到 onMeasure
的地方在看一下我们没有看完的代码
|
好了到此为止,整个测量过程基本上清楚了,下面我们根据一张时序图回顾一下整个流程
participant RecyclerView as A |
可以看出 RecyclerView
在整个测量过程还是整个流程的主导,LayoutManager
更多像是一个提供具体配置参数的。这个表可以作为我们自定义 LayoutManager
时的一个参考。
onLayout
继续看布局的相关方法,首先从 RecyclerView
的 onLayout
方法开始
protected void onLayout(boolean changed, int l, int t, int r, int b) { |
在 onLayout
中 RecyclerView
并没有做什么多余的操作,而是直接调用了 dispatchLayout
方法,这个方法会根据我们在 onMeasure
中的行为判断是否需要调用 dispatchLayoutStep1
和 dispatchLayoutStep2
,但是无论哪种情况都会通过 setExactMeasureSpecsFrom
给 LayoutManager
设置一个确切的宽高,最后调用 dispatchLayoutStep3
方法。
private void dispatchLayoutStep3() { |

这就结束了?,没错到此为止 LinearLayoutManager
或者说 RecyclerView
的 auto measure 就是这样的,当然 LayoutManager
还有一些其他功能这里还没有涉及到或者没有展开,后面遇到再进行说明。
Recycler
按照顺序这里应该是本应该是 Adapter
,但是我发现如果没有 Recycler
存在 Adapter
根本玩不下去,看名字 Recycler
就感觉像是 RecyclerView
的核心,确实它也掌管了所有 ChildView
的生成、复用、回收,确实也是核心,首先我们介绍一下 Recycler
中的几个缓存队列
mChangedScrap
item被标记为更新、有动画且动画支持变化mAttachedScrap
mCachedViews
Recycler
也还是得从测量过程中的 LayoutChunk
说起,虽然这个 Recycler
对象在一开始 onLayoutChildren
就作为参数传递到了 LayoutManager
,但是一直没有正经的使用它。
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, |
layoutChunk
根本意义上说也还没有使用 Recycler
对象,但是这里算上获取 childView
的一个起点,所以我们从这里开始分析,后续的几个方法也都没有做太多工作。到了 tryGetViewHolderForPositionByDeadline
真正的逻辑开始了。代码之前我们先整理一下逻辑,这个方法的的主要工作如下
- 如果进行了
PreLayout
则会优先从mChangedScrap
中查找ViewHolder
,PreLayout
这个行为发生在dispatchLayoutStep1
中,虽然是PreLayout
但是终究还是会去onLayoutChildren
,然后最后还是会调用tryGetViewHolderForPositionByDeadline
,所以本质上来说第一次来步骤1肯定会跳过
ViewHolder tryGetViewHolderForPositionByDeadline(int position, |