滚动RecyclerView以在顶部显示所选项目

Dis*_*two 192 android scroll android-recyclerview

我正在寻找一种滚动方式以RecyclerView在顶部显示所选项目的方法.

ListView我能够通过这样做,scrollTo(x,y)并获得了需要为中心元素的顶部.

就像是:

@Override
public void onItemClick(View v, int pos){
    mylistView.scrollTo(0, v.getTop());
}
Run Code Online (Sandbox Code Playgroud)

问题是RecyclerView当使用它的scrollTo方法时返回错误

RecyclerView不支持滚动到绝对位置

如何滚动a RecyclerView以将所选项目放在视图顶部?

Nir*_*raj 360

如果您使用的是LinearLayoutManager或StaggeredGridLayoutManager,它们每个都有一个scrollToPositionWithOffset方法,该方法从RecyclerView的开头获取项目开头的位置和偏移量,这似乎可以完成您的需要(设置偏移量) 0应该与顶部对齐).

例如:

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);
Run Code Online (Sandbox Code Playgroud)

  • 如果有人需要这个来恢复RecyclerView的滚动位置,这就是如何保存滚动位置(方法scrollToPositionWithOffset的两个参数):int index = linearLayoutManager.findFirstVisibleItemPosition(); 查看v = linearLayoutManager.getChildAt(0); int top =(v == null)?0:(v.getTop() - linearLayoutManager.getPaddingTop()); (32认同)
  • 如果我想"顺利"滚动到顶部怎么办? (17认同)

小智 86

如果您正在寻找垂直LinearLayout Manager,您可以使用自定义实现平滑滚动LinearSmoothScroller:

import android.content.Context;
import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;

public class SnappingLinearLayoutManager extends LinearLayoutManager {

    public SnappingLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return SnappingLinearLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在循环视图中使用layoutmanager的实例,然后调用 recyclerView.smoothScrollToPosition(pos);将平滑滚动到选定位置到回收器视图的顶部

  • 我是否正确地观察到这只适用于仍然有足够的/在它们之下的物品来填充剩余的`RecyclerView`?这就是说:这似乎不适用于最后一项 - 无论`SNAP_TO_START`,`RecyclerView`只会滚动,直到项目在底部变得可见,但不会一直向上移动.有关如何实现这一目标的任何想法?(我通过在`RecyclerView`上设置自定义填充来解决这个问题,但这似乎并不正确...) (6认同)
  • Kotlin 中相同 => https://gist.github.com/Kevinrob/4f32a6b971930cdc49f06be8dce6403c (3认同)
  • 真正有用的答案!我还在 TopSnappedSmoothScroller 中为水平列表覆盖了`getHorizo​​ntalSnapPreference()`。 (2认同)

小智 47

//滚动项目pos

linearLayoutManager.scrollToPositionWithOffset(pos, 0);
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法顺利完成这项工作? (6认同)
  • @Ashkan /sf/ask/2186462841/ (2认同)

Zer*_*ero 22

你只需要打电话recyclerview.scrollToPosition(position).没关系!

如果要在适配器中调用它,只需让适配器具有recyclerview实例或包含recyclerview的活动或片段,而不是实现其中的方法getRecyclerview().

我希望它可以帮到你.

  • 这对我有用 - recyclerView.scrollToPosition(0); 把我放在首位. (2认同)
  • 那不起作用,您必须使用linearLayoutManager.scrollToPositionWithOffset(pos,0); (2认同)

小智 14

如果要自动滚动而不显示滚动动作,则需要编写以下代码:

mRecyclerView.getLayoutManager().scrollToPosition(position);
Run Code Online (Sandbox Code Playgroud)

如果要显示滚动动作,则需要添加以下代码。=> 步骤 1:您需要声明 SmoothScroller。

RecyclerView.SmoothScroller smoothScroller = new
                LinearSmoothScroller(this.getApplicationContext()) {
                    @Override
                    protected int getVerticalSnapPreference() {
                        return LinearSmoothScroller.SNAP_TO_START;
                    }
                };
Run Code Online (Sandbox Code Playgroud)

=> 步骤 2:您需要将此代码添加到要执行滚动到特定位置的任何事件。=>首先,您需要将目标位置设置为 SmoothScroller。

smoothScroller.setTargetPosition(position);
Run Code Online (Sandbox Code Playgroud)

=> 然后你需要将 SmoothScroller 设置为 LayoutManager。

mRecyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
Run Code Online (Sandbox Code Playgroud)


use*_*515 11

与速度调节器相同

public class SmoothScrollLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 110f;
private Context mContext;

public SmoothScrollLinearLayoutManager(Context context,int orientation, boolean reverseLayout) {
    super(context,orientation,reverseLayout);
    mContext = context;
}

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                   int position) {
    RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext()){
        //This controls the direction in which smoothScroll looks for your view
        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return new PointF(0, 1);
        }

        //This returns the milliseconds it takes to scroll one pixel.
        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }
    };
    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}


private class TopSnappedSmoothScroller extends LinearSmoothScroller {
    public TopSnappedSmoothScroller(Context context) {
        super(context);

    }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        return SmoothScrollLinearLayoutManager.this
                .computeScrollVectorForPosition(targetPosition);
    }

    @Override
    protected int getVerticalSnapPreference() {
        return SNAP_TO_START;
    }
}
}
Run Code Online (Sandbox Code Playgroud)


Bel*_*loo 10

我在这里可以添加的是如何使其与DiffUtil和一起工作ListAdapter

您可能会注意到,如果在 后立即recyclerView.scrollToPosition(pos)调用,则调用or(recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, offset)将不起作用。这是因为 diff 在后台线程中查找更改,然后异步通知适配器有关更改的信息。在 SO 上,我看到了几个错误的答案以及不必要的延迟等来解决这个问题。adapter.submitList

为了正确处理这种情况,submitList有一个回调,当应用更改时会调用该回调。

因此,在这种情况下,正确的 kotlin 实现是:

//memorise target item here and a scroll offset if needed
adapter.submitList(items) { 
    val pos = /* here you may find a new position of the item or just use just a static position. It depends on your case */
    recyclerView.scrollToPosition(pos) 
}
//or
adapter.submitList(items) { recyclerView.smoothScrollToPosition(pos) }
//or etc
adapter.submitList(items) { (recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, offset) }
Run Code Online (Sandbox Code Playgroud)

  • 您提到了重要的一点:“更改发生在后台线程中,然后异步通知适配器有关更改的信息”。特恩克斯。 (2认同)

Ami*_*emi 9

只需简单地调用此方法:

((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(yourItemPosition,0);
Run Code Online (Sandbox Code Playgroud)

代替:

recyclerView.scrollToPosition(yourItemPosition);
Run Code Online (Sandbox Code Playgroud)


Luc*_*cem 9

我不知道为什么我没有找到最佳答案,但它真的很简单。

recyclerView.smoothScrollToPosition(position);
Run Code Online (Sandbox Code Playgroud)

没有错误

创建动画

  • 这不会将单击的项目滚动到顶部 - 这首先是问题所在。 (2认同)

小智 7

尝试一下对我有用的东西!

创建一个变量 private static int displayedposition = 0;

现在,您可以在Activity中找到RecyclerView的位置.

myRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                LinearLayoutManager llm = (LinearLayoutManager) myRecyclerView.getLayoutManager();


                displayedposition = llm.findFirstVisibleItemPosition();


            }
        });
Run Code Online (Sandbox Code Playgroud)

将此语句放在您希望它将前一个站点显示在视图中的位置.

LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        llm.scrollToPositionWithOffset(displayedposition , youList.size());
Run Code Online (Sandbox Code Playgroud)

那就是它,它对我来说很好\ o /


tsi*_*iro 6

在点击按钮后刷新RecyclerView后我做了什么来恢复滚动位置:

if (linearLayoutManager != null) {

    index = linearLayoutManager.findFirstVisibleItemPosition();
    View v = linearLayoutManager.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
    Log.d("TAG", "visible position " + " " + index);
}

else{
    index = 0;
}

linearLayoutManager = new LinearLayoutManager(getApplicationContext());
linearLayoutManager.scrollToPositionWithOffset(index, top);
Run Code Online (Sandbox Code Playgroud)

在创建linearLayoutManager对象之前从顶部获取第一个可见项的偏移量,并在实例化之后调用LinearLayoutManager对象的scrollToPositionWithOffset.


Ana*_*lii 5

介绍

没有一个答案解释如何在顶部显示最后一项。因此,答案仅适用于在其上方或下方仍有足够项目来填充剩余 的项目RecyclerView。例如,如果有 59 个元素,并且选择了第 56 个元素,则它应该位于顶部,如下图所示:

例子

那么,让我们在下一段中看看如何实现这一点。

解决方案

我们可以通过使用oflinearLayoutManager.scrollToPositionWithOffset(pos, 0)中的附加逻辑来处理这些情况- 通过在最后一项下方添加自定义边距(如果最后一项不可见,则意味着有足够的空间填充 )。自定义边距可能是根视图高度和项目高度之间的差异。因此,您的for将如下所示:AdapterRecyclerViewRecyclerView AdapterRecyclerView

...
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    ...

    int bottomHeight = 0;
    int itemHeight = holder.itemView.getMeasuredHeight();
    // if it's the last item then add a bottom margin that is enough to bring it to the top
    if (position == mDataSet.length - 1) {
        bottomHeight = Math.max(0, mRootView.getMeasuredHeight() - itemHeight);
    }
    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)holder.itemView.getLayoutParams();
    params.setMargins(0, 0, params.rightMargin, bottomHeight);
    holder.itemView.setLayoutParams(params);

    ...
} 
...
Run Code Online (Sandbox Code Playgroud)