setAdapterInternal
方法主要作用是将传进来的 adapter
保存到 mAdapter
变量。之后调用了 requestLayout
方法。
public void requestLayout() {
if (this.mEatRequestLayout == 0 && !this.mLayoutFrozen) {
super.requestLayout();
} else {
this.mLayoutRequestEaten = true;
}
}
requestLayout
方法又调用了父类的 requestLayout
方法,最终调用了 View
的 requestLayout
方法。
public void requestLayout() {
…
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
…
}
上面的 mParent
的真正实例为 ViewRootImpl
,也就是说执行了 ViewRootImpl
的 requestLayout
方法。
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
scheduleTraversals
方法被执行,意味着后续开始执行 RecyclerView
的 onMeasure
、onLayout
、onDraw
方法,之后RecyclerView
中子视图就展示出来了。
这里我们将 onLayout
方法单拎出来进行分析,因为 RecyclerView
之所以能适配多种滚动布局,主要是 onLayout
方法发挥作用。
protected void onLayout(boolean changed, int l, int t, int r, int b) {
…
this.dispatchLayout();
…
}
onLayout
方法接着调用了 dispatchLayout
方法。
void dispatchLayout() {
…
mState.mIsMeasuring = false;
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
}
…
dispatchLayoutStep3();
}
dispatchLayout
方法依次调用了 dispatchLayoutStep1
、dispatchLayoutStep2
、dispatchLayoutStep3
方法。
我们首先看 dispatchLayoutStep1
方法。
private void dispatchLayoutStep1() {
…
if (mState.mRunPredictiveAnimations) {
…
mLayout.onLayoutChildren(mRecycler, mState);
…
} else {
clearOldPositions();
}
…
}
dispatchLayoutStep1
方法中调用了 mLayout
的 onLayoutChildren
方法。上面分析告诉我们,mLayout
就是 LayoutManager
,所以我们转到 LayoutManager
的 onLayoutChildren
方法。
public void onLayoutChildren(Recycler recycler, State state) {
Log.e(TAG, "You must override onLayoutChildren(Recycler recycler, State state) ");
}
onLayoutChildren
方法是一个空实现,其具体实现在各个子类中。我们拿 LinearLayoutManager
进行分析,看其中 onLayoutChildren
的实现。
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
// layout algorithm:
// 1) by checking children and other variables, find an anchor coordinate and an anchor
// item position.
// 2) fill towards start, stacking from bottom
// 3) fill towards end, stacking from top
// 4) scroll to fulfill requirements like stack from bottom.
// create layout state
…
if (mAnchorInfo.mLayoutFromEnd) {
…
} else {
// fill towards end
updateLayoutStateToFillEnd(mAnchorInfo);
mLayoutState.mExtra = extraForEnd;
fill(recycler, mLayoutState, state, false);
endOffset = mLayoutState.mOffset;
final int lastElement = mLayoutState.mCurrentPosition;
if (mLayoutState.mAvailable > 0) {
extraForStart += mLayoutState.mAvailable;
}
// fill towards start
updateLayoutStateToFillStart(mAnchorInfo);
mLayoutState.mExtra = extraForStart;
mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
fill(recycler, mLayoutState, state, false);
startOffset = mLayoutState.mOffset;
if (mLayoutState.mAvailable > 0) {
extraForEnd = mLayoutState.mAvailable;
// start could not consume all it should. add more items towards end
updateLayoutStateToFillEnd(lastElement, endOffset);
mLayoutState.mExtra = extraForEnd;
fill(recycler, mLayoutState, state, false);
endOffset = mLayoutState.mOffset;
}
}
…
}
onLayoutChildren
方法中的注释已经为我们说明了 RecyclerView
的布局算法,mAnchorInfo
为布局锚点信息,包含了子控件在Y轴上起始绘制偏移量(coordinate),itemView
在 Adapter
中的索引位置(position)和布局方向(mLayoutFromEnd)-表示start、end方向。该方法的功能是:确定布局锚点,并以此为起点向开始和结束方向填充 ItemView
,如下图所示。
在 onLayoutChildren
方法中,调用了 fill
方法,从该方法名可以知道,该方法应该是将子控件加入到RecyclerView
中的。
int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
RecyclerView.State state, boolean stopOnFocusable) {
…
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
…
layoutChunk(recycler, state, layoutState, layoutChunkResult);
…
}
…
return start - layoutState.mAvailable;
}
fill
方法中循环调用了 layoutChunkResult
方法。
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
View view = layoutState.next(recycler);
…
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (layoutState.mScrapList == null) {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addView(view);
} else {
addView(view, 0);
}
} else {
…
}
measureChildWithMargins(view, 0, 0);
result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view);
int left, top, right, bottom;
…
layoutDecoratedWithMargins(view, left, top, right, bottom);
…
result.mFocusable = view.hasFocusable();
}
layoutChunk
方法中,layoutState的next方法将从 Recycler
获取的 View
添加到 RecyclerView
中,从而完成了整个 RecyclerView
的布局。
以上就是 RecyclerView
渲染过程的源码分析,接下来我们来分析一下 RecyclerView
的滑动过程。
RecyclerView
本质上就是一个 View
,所以我们从它的 onTouchEvent
方法入手进行分析。
public boolean onTouchEvent(MotionEvent e) {
…
switch (action) {
case MotionEvent.ACTION_DOWN: {
…
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
…
} break;
case MotionEvent.ACTION_MOVE: {
小福利:
在当下这个碎片化信息环境的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了
很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021大厂最新Android面试真题解析
各个模块学习视频:如数据结构与算法
只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
或直接点击这里前往我的GitHub中下载,就可以白嫖啦,记得给文章点个赞哦。
0049235)]
或直接点击这里前往我的GitHub中下载,就可以白嫖啦,记得给文章点个赞哦。