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


214

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

在A中,ListView我能够通过使用scrollTo(x,y)并获取需要居中的元素的顶部来做到这一点。

就像是:

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

问题是RecyclerView使用scrollTo方法说时返回错误

RecyclerView不支持滚动到绝对位置

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

Answers:


404

如果您使用LinearLayoutManager或Staggered GridLayoutManager,则它们每个都有一个scrollToPositionWithOffset方法,该方法同时获取位置以及项目开始位置相对于开始位置的偏移量RecyclerView,这似乎可以满足您的需要(将偏移量设置为0应该与顶部对齐)。

例如:

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);

34
如果有人需要它来恢复RecyclerView的滚动位置,这就是保存滚动位置(方法scrollToPositionWithOffset的两个参数)的方法:int index = linearLayoutManager.findFirstVisibleItemPosition(); 查看v = linearLayoutManager.getChildAt(0); int top =(v == null)吗?0:(v.getTop()-linearLayoutManager.getPaddingTop());
DominicM

我似乎对此一无所知,是什么时候调用scrollToPosition?如果选择侦听器在各个视图上,则如何通知RecyclerView对象(可以访问其布局管理器,可以调用scrolToPosition),该对象已被选中?
诺诺斯2015年

@Nonos,您可以先在RecylerView.setLayoutManager()中存储使用的LayoutManager,然后直接访问它。像这样:LinearLayoutManager llm = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(llm); ...(代码稍后)... llm.scrollToPositionWithOffset(2,20);
尼拉伊,2015年

19
如果我想“平滑地”滚动到顶部怎么办?
蒂亚戈

@Tiago,我还没有玩过,但是这三部分的系列文章可能会有所帮助:blog.stylingandroid.com/scrolling-recyclerview-part-1
Niraj 2015年

93

如果您正在寻找垂直的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;
        }
    }
}

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


1
确实有用的答案!我还在getHorizontalSnapPreference()TopSnappedSmoothScroller中为“水平”列表重写。
Juan Saravia 2015年

6
我是否正确地指出,这仅适用于在其后/下方仍具有足够的余量来填充剩余物的物品RecyclerView?这就是说:这似乎没有工作的最后一个项目-不管的SNAP_TO_STARTRecyclerView唯一滚动,直到该项目在底部变得可见,但不动它一路攀升。关于如何实现这一目标的任何想法?(我已经通过在上设置自定义填充来解决此问题,RecyclerView但这似乎并不正确...)
david.mihola


有时项目剂量变得集中,我有一个可绘制的项目视图焦点。
YLS

1
@ david.mihola您找到了“正确的”方法吗?我在自己的recyclerview中设置了自定义填充,但遇到了一些奇怪的问题……
bernardo.g


28

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

如果要在适配器中调用它,只需让适配器具有recyclerview实例或包含recyclerview的活动或片段,然后getRecyclerview()在其中实现该方法即可。

希望对您有所帮助。


2
这对我有用-recyclerView.scrollToPosition(0); 把我放在首位
Ray Hunter

2
那不起作用,您必须使用linearLayoutManager.scrollToPositionWithOffset(pos,0);
Anil Ugale

@Anil Ugale废话。当然可以。您可以将任何LayoutManager用于RecyclerView。为什么以后要滚动时要关心它?我认为您做错了什么。Recyclerview.scrollToPosition(position)是调用LayoutManager.scrollToPosition(position)的便捷方法。
令人难以置信的

1
@TheincredibleJan并非在所有情况下都有效,而layoutManager通常仅负责您的信息滚动。
穆罕默德

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;
    }
}
}

8

尝试对我有用的东西!

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

现在查看您的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();


            }
        });

将此语句放在您希望将其显示在视图中的旧站点的位置。

LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        llm.scrollToPositionWithOffset(displayedposition , youList.size());

就是这样,对我来说效果很好\ o /


7

只需简单地调用此方法:

((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(yourItemPosition,0);

代替:

recyclerView.scrollToPosition(yourItemPosition);

“代替”?Distwo没有提及“ scrollToPosition”。如果他使用过它,就不会有任何问题。按预期方式滚动scroll()。
令人难以置信的

1
奇怪的是,使用scrollToPositionWithOffset对我有用,而recyclerview.scrollToPosition没有。尽管,我会要求Amir将RecyclerView更改为recyclerview,因为它可以感觉到方法是静态的,而并非静态的。
Mohit

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);

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


6

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

recyclerView.smoothScrollToPosition(position);

没有错误

制作动画


您将把它放在哪里活动或适配器?
阿诺德·布朗

3

滚动到特定位置
,这对我很有帮助。通过单击侦听器,您可以在适配器中获得位置

layoutmanager.scrollToPosition(int position);

3
If you want to scroll automatic without show scroll motion then you need to write following code:

**=> mRecyclerView.getLayoutManager().scrollToPosition(position);**

If you want to display scroll motion then you need to add following code.
=>Step 1: You need to declare SmoothScroller.

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

=>step 2: You need to add this code any event you want to perform scroll to specific position.
=>First you need to set target position to SmoothScroller.

**smoothScroller.setTargetPosition(position);**

=>Then you need to set SmoothScroller to LayoutManager.
                        **mRecyclerView.getLayoutManager().startSmoothScroll(smoothScroller);**

3

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

RecyclerView-已选择元素56 我们可以处理由使用的情况下linearLayoutManager.scrollToPositionWithOffset(pos, 0)和一个额外的逻辑成AdapterRecyclerView-通过增加的最后一项下方的自订利润率(如果最后一个项目是不可见的话,那就意味着有足够的空间填充的RecyclerView)。自定义边距可以是根视图高度和项目高度之间的差异。因此,您的 Adapterfor RecyclerView如下所示:

...
@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);

    ...
} 
...

2

就我而言,我RecyclerView有这样的填充顶部

<android.support.v7.widget.RecyclerView
     ...
     android:paddingTop="100dp"
     android:clipToPadding="false"
/>

然后将项目滚动到顶部,我需要

recyclerViewLinearLayoutManager.scrollToPositionWithOffset(position, -yourRecyclerView.getPaddingTop());

1

如果你LayoutManagerLinearLayoutManager,你使用scrollToPositionWithOffset(position,0);它,它会让你的项目的第一个可见项目在列表中。否则,您可以smoothScrollToPositionRecyclerView直接。

我最终使用了以下代码。

 RecyclerView.LayoutManager layoutManager = mainList.getLayoutManager();
        if (layoutManager instanceof LinearLayoutManager) {
            // Scroll to item and make it the first visible item of the list.
            ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, 0);
        } else {
            mainList.smoothScrollToPosition(position);
        }

-2

我使用下面的代码将一个项目(thisView)平滑滚动到顶部。
它也适用于具有不同高度的视图的GridLayoutManager:

View firstView = mRecyclerView.getChildAt(0);
int toY = firstView.getTop();
int firstPosition = mRecyclerView.getChildAdapterPosition(firstView);
View thisView = mRecyclerView.getChildAt(thisPosition - firstPosition);
int fromY = thisView.getTop();

mRecyclerView.smoothScrollBy(0, fromY - toY);

似乎可以很好地工作,可以快速解决。


1
什么是价值thisPosition
2013年

它是您要平滑滚动至的位置
Jan Rabe'Sep

为什么不不用任何计算就简单地使用smoothScrollToPosition(int position)?从头开始没有关系,对吗?
令人难以置信的
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.