public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {
在RecyclerView的 layoutManager可以布局和定位ItemVIew,以及使用者看不见的item的回收策略,通过改变layoutManager,RecyclerView可以实现一个标准的垂直滚动的列表,统一网格,交错网格,水平滚动集合和更多。系统提供了几种通用的样式。
从上面的翻译可以看出,它的作用就是负责RecycleView对ItemView的测量和布局以及回收策略的实现
系统提供几种 LayoutManager通用样式分别为:
(1)LinearLayoutManager(线性布局管理器)
public class LinearLayoutManager extends RecyclerView.LayoutManager implements
ItemTouchHelper.ViewDropHandler, RecyclerView.SmoothScroller.ScrollVectorProvider {
(2)GridLayoutManager(表格布局管理器)
public class GridLayoutManager extends LinearLayoutManager {}
(3)StaggeredGridLayoutManager (瀑布流布局管理器)
public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager implements
RecyclerView.SmoothScroller.ScrollVectorProvider {}
由它的内部抽象类RecyclerView.LayoutManager实现,RecyclerView负责绘制所有decoration;ItemView的绘制由ViewGroup处理,RecyclerView不负责绘制itemVIew,并且是逐个执行的,也就是说执行完一个子控件的onMeasure和onlayout过程,在执行下一个。如下代码:
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
// mLayout测量过程
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
if (mState.mLayoutStep == State.STEP_START) {
//mLayout布局过程
dispatchLayoutStep2();
}
......代码略
}
看下方法:dispatchLayoutStep2()
private void dispatchLayoutStep2() {
......代码略
mLayout.onLayoutChildren(mRecycler, mState);
......代码略
}
进入到onlayoutChildren方法
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
...略
if (mAnchorInfo.mLayoutFromEnd) {
...略
fill(recycler, mLayoutState, state, false);
// fill towards start
fill(recycler, mLayoutState, state, false);
...略
} else {
...略
// fill towards end
fill(recycler, mLayoutState, state, false);
// fill towards start
fill(recycler, mLayoutState, state, false);
...略
}
...略
}
onLayoutChildren确定布局锚点,以此为起点向开始和结束方向填充ItemView,至于填充即使在fill方法里了,这段代码做的工作 如下:
接下来进入到fill()方法,看看是如何填充的
int fill(...) {
//循环调用layoutChunk
while (...) {
layoutChunk(...);
}
}
就是一些系列的判断循环调用layoutchunk方法,进入layoutchunk方法
void layoutChunk(...) {
addView(view);
}
走到这里就是调用ViewGroup的addview方法了,添加View。
以上就是RecyclerView的onMeasure的方法里执行layoutManager的onMeasure和onlayout方法。
void dispatchLayout() {
...
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
...
dispatchLayoutStep2();
}
dispatchLayoutStep3();
...
}
发现RecyclerView的layout方法也会执行dispatchLayoutStep()方法,就是也会走layoutManager的onMeasure和onlayout方法。
RecyclerView的layout和measure里都执行了layoutManager的测量和布局方法,那么是执行两边layoutManager的测量和布局方法,还是只执行一次呢?
在RecycleView’中的onMeasure中会判断如果RecycleView支持WRAP_CONTENT,先确定了子控件的大小及位置后,再由此设置RecyclerView的大小;如果是其它情况(测量模式为EXACTLY),子控件的measure及layout过程就会延迟至RecyclerView的layout过程
#####RecyclerView的onDraw方法#####
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
final int count = mItemDecorations.size();
for (int i = 0; i < count; i++) {
mItemDecorations.get(i).onDraw(c, this, mState);
}
}
ItemDecoration是啥?
即使保存了ItemView四个方向的偏移量值,可以想象成padding,测量时itemView的itemDecoration保存的对应的偏移量的值也会被计算进去。
在measureChildWithMargins方法中调用获取itemDecoration
的值
public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
...
final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
...
child.measure(widthSpec, heightSpec);
}
}
如下就是itemDecoration的偏移量大小+itemVIew自身的大小
分析Recycle的
public boolean onTouchEvent(MotionEvent e) {
...
switch (action) {
...
case MotionEvent.ACTION_MOVE: {
//手指滑动距离>滑动阀值 则为SCROLL_STATE_DRAGGING
//进行滚动
if (mScrollState == SCROLL_STATE_DRAGGING) {
scrollByInternal();
}
break;
...
case MotionEvent.ACTION_UP: {
//手指抬起后 获取之前的滑动距离和时间算出平均速度,由
//VelocityTracker实现的,然后传入filing进行滚动
...
此处执行fling()方法
} break;
...
}
...
}
scrollByInternal()和fling()方法都会调用相应的layoutManager的子类的,比如使用的是LinearLayoutManager,则调用LinearLayoutManager的scrollBy方法
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
...
//此处调用fill方法 进行addview了
final int consumed = mLayoutState.mScrollingOffset
+ fill(recycler, mLayoutState, state, false);
...
//开始平移View
mOrientationHelper.offsetChildren(-scrolled);
}
综上述分析就是: Scroller每次计算的滑动偏移量是很小的一部分,而RecyclerView就会根据这个偏移量,确定是平移ItemView,还是除了平移还需要再创建新ItemView
如下图:
作用:RecycleView的回收机制由它实现
结构:scrapped、cached和exCached集合定义在RecyclerView.Recycler中,
内部集合:
(1)scrapped:存放 删除的ItemView
(2)cached:以及缓存和二级缓存 结合默认大小为2
(3)exCached:默认没有实现,需要自己实现
(4)recycled:在RecyclerView.RecycledViewPool中,用于区分Item,用ItemType,本身是个map集合,RecyclerView.RecycledViewPool可以实现在不同的RecyclerView之间共享ItemView,只要为这些不同RecyclerView设置同一个RecyclerView.RecycledViewPool就可以了。
使用的地方:在fill时判断:
首先判断集合cached是否満了,如果已満就从cached集合中移出一个到recycled集合中去,再把新的ItemView添加到cached集合;如果不満就将ItemView直接添加到cached集合。
最后exCached集合是我们自己创建的,所以添加删除元素也要我们自己实现。
(1)RecycleView对数据集有四种操作:ADD、REMOVE、UPDATE、MOVE,封装在了AdapterHelper.UpdateOp
static class UpdateOp {
static final int ADD = 1;
static final int REMOVE = 1 << 1;
static final int UPDATE = 1 << 2;
static final int MOVE = 1 << 3;
static final int POOL_SIZE = 30;
(2)RecyclerView.RecyclerViewDataObserver.triggerUpdateProcessor()执行时,根据这个等待队列中的信息,对所有子控件重新测量、布局并绘制且执行动画。以上就是我们调用Adapter.notifyItemXXX()系列然后调用RecyclerView.onLayout()会随后调用执行onLayout中的dispatchLayoutStep1()初始化数据,dispatchLayoutStep2(),测量和布局,dispatchLayoutStep3就是添加动画。