移动开发最新RecyclerView实现吸顶效果项目实战(四):RecyclerView原理解析,零基础学习android

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
Android进阶视频+面试资料部分截图

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

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: {

if (mScrollState == SCROLL_STATE_DRAGGING) {

mLastTouchX = x - mScrollOffset[0];

mLastTouchY = y - mScrollOffset[1];

if (scrollByInternal(

canScrollHorizontally ? dx : 0,

canScrollVertically ? dy : 0,

vtev)) {

getParent().requestDisallowInterceptTouchEvent(true);

}

if (mGapWorker != null && (dx != 0 || dy != 0)) {

mGapWorker.postFromTraversal(this, dx, dy);

}

}

} break;

case MotionEvent.ACTION_POINTER_UP: {

} break;

case MotionEvent.ACTION_UP: {

} break;

case MotionEvent.ACTION_CANCEL: {

} break;

}

return true;

}

onTouchEvent 方法中主要关注的是 actionMotionEvent.ACTION_MOVE 的情况,在滑动过程中调用了scrollByInternal 方法。

boolean scrollByInternal(int x, int y, MotionEvent ev) {

if (mAdapter != null) {

if (x != 0) {

consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);

unconsumedX = x - consumedX;

}

if (y != 0) {

consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);

unconsumedY = y - consumedY;

}

}

return consumedX != 0 || consumedY != 0;

}

当上下滑动时,垂直方向上的y偏移量是不等于0的,从而执行了 LayoutManagerscrollVerticallyBy 方法。我们拿 LinearLayoutManagerscrollVerticallyBy 来举例。

public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,

RecyclerView.State state) {

if (mOrientation == HORIZONTAL) {

return 0;

}

return scrollBy(dy, recycler, state);

}

当上下滑动时,执行了 scrollBy 方法。

int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {

final int consumed = mLayoutState.mScrollingOffset

  • fill(recycler, mLayoutState, state, false);

mOrientationHelper.offsetChildren(-scrolled);

return scrolled;

}

scrollBy 方法中又执行了 fill 方法,该方法的作用是向可填充区域填充 itemView,我们具体看一下 fill 方法的实现。

int fill(RecyclerView.Recycler recycler, LayoutState layoutState,

RecyclerView.State state, boolean stopOnFocusable) {

while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {

layoutChunkResult.resetInternal();

layoutChunk(recycler, state, layoutState, layoutChunkResult);

if (layoutChunkResult.mFinished) {

break;

}

layoutState.mOffset += layoutChunkResult.mConsumed * layoutState.mLayoutDirection;

}

return start - layoutState.mAvailable;

}

fill方法中又调用了layoutChunk方法。

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 {

if (mShouldReverseLayout == (layoutState.mLayoutDirection

== LayoutState.LAYOUT_START)) {

addDisappearingView(view);

} else {

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
Android进阶视频+面试资料部分截图

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

tate.LAYOUT_START)) {

addDisappearingView(view);

} else {

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
[外链图片转存中…(img-wJW7M0s5-1715451111325)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值