recycleview可见位置_RecyclerView获取指定位置的ItemView

本文探讨在RecyclerView中实现视频播放列表时遇到的问题,即当尝试通过`scrollToPosition()`自动滚动播放下一个item时,有时无法获取到目标item。通过分析源码发现,`scrollToPosition()`会触发`requestLayout()`,可能导致未准备好显示的item。改用`scrollBy()`方法,结合item高度,成功实现了平滑滚动并正确获取item。分析源码揭示了两者内部的工作原理。
摘要由CSDN通过智能技术生成

tips:观察AndroidStudio的调用堆栈,对看源码分析问题很有帮助

业务场景

RecyclerView+LinearLayoutManager实现视频播放列表。当前视频播放完成后,自动向上滚动一个item,并且开始播放。

遇到问题

1.问题代码

//滑动一个item

recyclerView.scrollToPosition((msg.arg1 + 1));

View childAt = layoutManager.findViewByPosition((msg.arg1 + 1));

if (childAt!=null){

//视频开始播放

NiceVideoPlayer niceVideoPlayer=childAt.findViewById(R.id.nice_video_player);

niceVideoPlayer.start();

}

当前屏幕上有3个item,从第0个开始播放。第0个播放完成,播放第1个。第1个播放完成,播放第2个,layoutManager.findViewByPosition都可以获取到item。加载position为3的item时,layoutManager.findViewByPosition返回null。奇怪的事,position为3的item已经显示在屏幕上。

2.修改后的代码

//742是一个item的高度

recyclerView.scrollBy(0,742);

View childAt = layoutManager.findViewByPosition((msg.arg1 + 1));

if (childAt!=null){

//视频开始播放

NiceVideoPlayer niceVideoPlayer=childAt.findViewById(R.id.nice_video_player);

niceVideoPlayer.start();

}

原因分析

1.recyclerView.scrollToPosition((msg.arg1 + 1))为啥不行(未完待续)

RecyclerView

public void scrollToPosition(int position) {

if (mLayoutFrozen) {

return;

}

stopScroll();

if (mLayout == null) {

Log.e(TAG, "Cannot scroll to position a LayoutManager set. "

+ "Call setLayoutManager with a non-null argument.");

return;

}

mLayout.scrollToPosition(position);

awakenScrollBars();

}

LinearLayoutManager

@Override

public void scrollToPosition(int position) {

mPendingScrollPosition = position;

mPendingScrollPositionOffset = INVALID_OFFSET;

if (mPendingSavedState != null) {

mPendingSavedState.invalidateAnchor();

}

requestLayout();

}

LinearLayoutManager

public void requestLayout() {

if (mRecyclerView != null) {

mRecyclerView.requestLayout();

}

}

RecyclerView.scrollToPosition最终调用了RecyclerView的request()方法,RecyclerVeiw的onMeasure(),onLayout()都会被调用,onDraw()方法可能别调用,这没分析完,下次再写。

2.recyclerView.scrollBy(0,742)为啥可以

RecyclerView

@Override

public void scrollBy(int x, int y) {

if (mLayout == null) {

Log.e(TAG, "Cannot scroll without a LayoutManager set. "

+ "Call setLayoutManager with a non-null argument.");

return;

}

if (mLayoutFrozen) {

return;

}

final boolean canScrollHorizontal = mLayout.canScrollHorizontally();

final boolean canScrollVertical = mLayout.canScrollVertically();

if (canScrollHorizontal || canScrollVertical) {

scrollByInternal(canScrollHorizontal ? x : 0, canScrollVertical ? y : 0, null);

}

}

RecyclerView

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

int unconsumedX = 0, unconsumedY = 0;

int consumedX = 0, consumedY = 0;

consumePendingUpdateOperations();

if (mAdapter != null) {

eatRequestLayout();

onEnterLayoutOrScroll();

TraceCompat.beginSection(TRACE_SCROLL_TAG);

fillRemainingScrollValues(mState);

if (x != 0) {

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

unconsumedX = x - consumedX;

}

if (y != 0) {

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

unconsumedY = y - consumedY;

}

TraceCompat.endSection();

repositionShadowingViews();

onExitLayoutOrScroll();

resumeRequestLayout(false);

}

if (!mItemDecorations.isEmpty()) {

invalidate();

}

if (dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset,

TYPE_TOUCH)) {

// Update the last touch co-ords, taking any scroll offset into account

mLastTouchX -= mScrollOffset[0];

mLastTouchY -= mScrollOffset[1];

if (ev != null) {

ev.offsetLocation(mScrollOffset[0]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值