「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
RecyclerView的使用我们其实都会了,但是它的原理是什么,我们还有不了解的,所以这篇文章主要是对源码进行分析
不管是View还是ViewGroup,必须有三大流程:测量、布局、绘制,所以我们先开看看RecyclerView的绘制流程
一、 onMeasure()
RecyclerView是继承ViewGroup,所以它的本质是自定义view,需要管理绘制流程,我们首先看onMeasure()过程 我们可以将它分为3种情况: (1) 如果当LayoutManager为null的时候,直接使用默认测量方法 (2) 设置了LayoutManager并开启了自动测量功能 (3) 设置了LayoutManager但是没有开启自动测量功能
protected void onMeasure(int widthSpec, int heightSpec) {
if (mLayout == null) {
...
}
if (mLayout.isAutoMeasureEnabled()) {
...
} else {
...
}
}
- 当LayoutManager为null的时候 直接调用defaultOnMeasure(widthSpec, heightSpec)方法 我们看看defaultOnMeasure()方法具体实现
void defaultOnMeasure(int widthSpec, int heightSpec) {
final int width = LayoutManager.chooseSize(widthSpec,
getPaddingLeft() + getPaddingRight(),
ViewCompat.getMinimumWidth(this));
final int height = LayoutManager.chooseSize(heightSpec,
getPaddingTop() + getPaddingBottom(),
ViewCompat.getMinimumHeight(this));
setMeasuredDimension(width, height);
}
- 设置了LayoutManager并开启了自动测量功能 (1) 会调用LayoutManager的onMeasure()方法
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
(2) 如果width和height都是确定的值,直接返回
mLastAutoMeasureSkippedDueToExact =
widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY;
if (mLastAutoMeasureSkippedDueToExact || mAdapter == null) {
return;
}
(3) 如果值不确定,需要根据子View来确定宽高
dispatchLayoutStep2();
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
- 设置了LayoutManager但是没有开启自动测量功能 (1) 如果RecyclerView已经设置了固定值,直接使用
if (mHasFixedSize) {
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
return;
}
(3) 没有固定值,进行测量
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
二、 onLayout()
onLayout()中的dispatchLayout()保证RecyclerView必须经历三个过程(dispatchLayoutStep1()、dispatchLayoutStep2()、dispatchLayoutStep3() ),一句话总结就是会根据onMeasure()执行到了哪个,然后会在onLayout()中把剩下的步骤执行
protected void onLayout(boolean changed, int l, int t, int r, int b) {
TraceCompat.beginSection(TRACE_ON_LAYOUT_TAG);
dispatchLayout();
TraceCompat.endSection();
mFirstLayoutComplete = true;
}
void dispatchLayout() {
if (mAdapter == null) {
return;
}
if (mLayout == null) {
return;
}
mState.mIsMeasuring = false;
...
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
} else if (mAdapterHelper.hasUpdates()
|| needsRemeasureDueToExactSkip
|| mLayout.getWidth() != getWidth()
|| mLayout.getHeight() != getHeight()) {
...
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
} else {
...
mLayout.setExactMeasureSpecsFrom(this);
}
dispatchLayoutStep3();
}
三、 onDraw()
- 将Children的绘制分发给ViewGroup;
- 将分割线的绘制分发给ItemDecoration
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);
}
}
绘制流程大概就完了,下一篇分析Recycler的缓存机制