[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都是先确定一个锚点位置,然后根据锚点,分别向上和向下去测量和布局子ViewLayoutState是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 中的几个缓存队列
mChangedScrapitem被标记为更新、有动画且动画支持变化mAttachedScrapmCachedViews
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, |