0
点赞
收藏
分享

微信扫一扫

RecyclerView实现吸顶效果项目实战(四),2021大厂Android面试题精选

爱情锦囊 2022-03-11 阅读 74
面试

setAdapterInternal 方法主要作用是将传进来的 adapter 保存到 mAdapter 变量。之后调用了 requestLayout 方法。

public void requestLayout() {

if (this.mEatRequestLayout == 0 && !this.mLayoutFrozen) {

super.requestLayout();

} else {

this.mLayoutRequestEaten = true;

}

}

requestLayout 方法又调用了父类的 requestLayout 方法,最终调用了 ViewrequestLayout 方法。

public void requestLayout() {

if (mParent != null && !mParent.isLayoutRequested()) {

mParent.requestLayout();

}

}

上面的 mParent 的真正实例为 ViewRootImpl,也就是说执行了 ViewRootImplrequestLayout 方法。

public void requestLayout() {

if (!mHandlingLayoutInLayoutRequest) {

checkThread();

mLayoutRequested = true;

scheduleTraversals();

}

}

scheduleTraversals 方法被执行,意味着后续开始执行 RecyclerViewonMeasureonLayoutonDraw 方法,之后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 方法依次调用了 dispatchLayoutStep1dispatchLayoutStep2dispatchLayoutStep3 方法。

我们首先看 dispatchLayoutStep1 方法。

private void dispatchLayoutStep1() {

if (mState.mRunPredictiveAnimations) {

mLayout.onLayoutChildren(mRecycler, mState);

} else {

clearOldPositions();

}

}

dispatchLayoutStep1 方法中调用了 mLayoutonLayoutChildren 方法。上面分析告诉我们,mLayout 就是 LayoutManager,所以我们转到 LayoutManageronLayoutChildren 方法。

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),itemViewAdapter 中的索引位置(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中下载,就可以白嫖啦,记得给文章点个赞哦。

举报

相关推荐

0 条评论