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

时间:2014-11-11 21:38:08

标签: android scroll android-recyclerview

我正在寻找一种方法来滚动RecyclerView以显示所选项目。

ListView中,我通过使用scrollTo(x,y)并获取需要居中的元素的顶部来实现这一目标。

类似的东西:

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

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

  

RecyclerView不支持滚动到绝对位置

如何滚动RecyclerView将所选项目置于视图顶部?

16 个答案:

答案 0 :(得分:330)

如果您使用的是LinearLayoutManager或交错的GridLayoutManager,则每个方法都有一个scrollToPositionWithOffset方法,该方法同时从项目开始处获取项目开头的位置和偏移量RecyclerView,看起来它可以完成你所需要的(将偏移设置为0应该与顶部对齐)。

例如:

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

答案 1 :(得分:82)

如果您正在寻找垂直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);将平滑滚动到所选位置到回收站视图的顶部

答案 2 :(得分:43)

//滚动项目pos

linearLayoutManager.scrollToPositionWithOffset(pos, 0);

答案 3 :(得分:17)

您只需致电recyclerview.scrollToPosition(position)即可。没关系!

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

我希望它可以帮到你。

答案 4 :(得分: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;
    }
}
}

答案 5 :(得分: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 :(得分:3)

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

function PreviousProduct() {
    $pages = ProductPage::get()->filter(array(
        'ParentID' => $this->ParentID,
        'Sort:LessThan' => $this->Sort
    ))->Sort('Sort')->reverse()->limit(1);

    if ($pages->count()) {
        return $pages->First();
    }

    $parent = $this->parent();
    $parentSiblings = ProductRange::get()->filter(array(
        'ParentID' => $parent->ParentID,
        'Sort:LessThan' => $parent->Sort
    ))->Sort('Sort')->reverse();

    foreach ($parentSiblings as $parentSibling) {
        $pages = ProductPage::get()->filter(array(
            'ParentID' => $parentSibling->ID
        ))->Sort('Sort')->reverse()->limit(1);

        if ($pages->count()) {
            return $pages->First();
        }
    }
    return false;
}

答案 7 :(得分:3)

如果您的LayoutManagerLinearLayoutManager,则可以在其上使用scrollToPositionWithOffset(position,0);,它将使您的商品成为列表中第一个可见的商品。否则,您可以直接在smoothScrollToPosition上使用RecyclerView

我最终使用了以下代码。

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

答案 8 :(得分:2)

在我的情况下,RecyclerView有一个像这样的填充顶部

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

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

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

答案 9 :(得分:1)

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

答案 10 :(得分:1)

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

recyclerView.smoothScrollToPosition(position);

没有错误

创建动画

答案 11 :(得分:1)

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

RecyclerView - element 56 is selected 我们可以通过使用linearLayoutManager.scrollToPositionWithOffset(pos, 0)Adapter的{​​{1}}中的附加逻辑来处理这些情况-通过在最后一项下方添加自定义边距(如果最后一项不可见,则意味着存在RecyclerView中有足够的空间。自定义边距可以是根视图高度和项目高度之间的差异。因此,您的RecyclerView的{​​{1}}如下所示:


Adapter

答案 12 :(得分:1)

请注意,如果 scrollToPosition 不起作用,请注意您的 RecyclerView 位于 NestedScrollView 内; refer to this post

答案 13 :(得分:0)

只需简单地调用此方法:

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

而不是:

RecyclerView.scrollToPosition(yourItemPosition);

答案 14 :(得分:0)

我可以在此处添加的内容是如何使其与DiffUtilListAdapter一起工作

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

为正确处理这种情况,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) }

答案 15 :(得分:-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);

似乎工作得很好,可以快速解决问题。