如何在Android中保存RecyclerView的滚动位置?

时间:2016-04-12 08:52:30

标签: android scroll android-recyclerview

我有一个Recycler视图,它位于SwipeRefreshLayout内部。此外,还可以打开另一个活动中的每个项目。 返回Recycler后,我需要滚动到所选项目,或前一个Y. 怎么做?

是的,我用Google搜索,在StackOverFlow中找到关于保存布局管理器实例的文章,如下所示:RecyclerView store / restore state between activities。 但是,它对我没有帮助。

更新

现在我有这种解决问题,当然,它也不起作用。

private int scrollPosition;

...//onViewCreated - it is fragment
recyclerView.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(llm);
data = new ArrayList<>();
adapter.setData(getActivity(), data);
recyclerView.setAdapter(adapter);
...

@Override
public void onResume() {
    super.onResume();
    recyclerView.setScrollY(scrollPosition);
}

@Override
public void onPause() {
    super.onPause();
    scrollPosition = recyclerView.getScrollY();
}

是的,我尝试过scrollTo(int,int) - 不能工作。

现在我尝试滚动,例如,Y = 100,但它根本没有滚动。

8 个答案:

答案 0 :(得分:36)

保存回收视图位置的当前状态@onPause:

    positionIndex= llManager.findFirstVisibleItemPosition();
    View startView = rv.getChildAt(0);
    topView = (startView == null) ? 0 : (startView.getTop() - rv.getPaddingTop());

恢复滚动位置@onResume:

    if (positionIndex!= -1) {
        llManager.scrollToPositionWithOffset(positionIndex, topView);
    }

或其他方式可以是@onPause:

long currentVisiblePosition = 0;
currentVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

恢复@onResume:

((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(currentVisiblePosition);
currentVisiblePosition = 0;

答案 1 :(得分:19)

很多这些答案似乎过于复杂化了。

LayoutManager支持onRestoreInstanceState开箱即用,因此无需保存滚动位置等。内置方法已经保存了像素完美位置。

示例片段代码(为清晰起见,删除了空检查等):

private Parcelable listState;
private RecyclerView list;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    listState=savedInstanceState.getParcelable("ListState");

}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putParcelable("ListState", list.getLayoutManager().onSaveInstanceState());

}

然后打电话

list.getLayoutManager().onRestoreInstanceState(listState);

将您的数据重新附加到RecyclerView

答案 2 :(得分:2)

使用您的回收商视图linearlayoutmanager获取滚动位置

int position = 0;
if (linearLayoutManager != null) {
   scrollPosition = inearLayoutManager.findFirstVisibleItemPosition();
}

并在恢复时使用以下代码

if (linearLayoutManager != null) {
  cardRecyclerView.scrollToPosition(mScrollPosition);
}

希望这有助于你

答案 3 :(得分:2)

从androidx recyclerView库的1.2.0-alpha02版本开始,现在可以对其进行自动管理。只需添加:

implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"

并使用:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

StateRestorationPolicy枚举有3个选项:

  • ALLOW-默认状态,在下一次布局传递中立即恢复RecyclerView状态
  • PREVENT_WHEN_EMPTY —仅在适配器不为空(adapter.getItemCount()> 0)时,才恢复RecyclerView状态。如果您的数据是异步加载的,那么RecyclerView会一直等到数据加载完毕,然后状态才能恢复。如果您有默认项(例如标头或装入进度指示器)作为适配器的一部分,则应使用PREVENT选项,除非使用MergeAdapter添加了默认项。 MergeAdapter等待所有适配器准备就绪,然后才恢复状态。
  • PREVENT-将所有状态恢复推迟到您设置ALLOW或PREVENT_WHEN_EMPTY之前。

请注意,在回答此问题时,recyclerView库仍处于alpha03中,但是 alpha阶段不适合用于生产目的

答案 4 :(得分:0)

要将位置保存到“偏好设置”中,请将其添加到onStop()

 int currentVisiblePosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
 getPreferences(MODE_PRIVATE).edit().putInt("listPosition", currentVisiblePosition).apply();

然后恢复这样的位置

 if (getItemCount() == 0) {
     int savedListPosition = getPreferences(MODE_PRIVATE).getInt("listPosition", 0);
     recyclerView.getLayoutManager().scrollToPosition(savedListPosition); }

这最后一个代码应添加到Adapter事件中(不确定女巫事件,但在我的情况下是onEvent()-com.google.firebase.firestore.EventListener)

答案 5 :(得分:0)

由于某些原因,关于如何在方向更改时如何保存和恢复your_scrolling_container中的滚动位置,存在很多令人误解的提示/建议。

获取当前滚动位置并将其保存在Activity的onSaveInstanceState中 扩展某个可滚动视图以在此处执行相同操作 防止活动在旋转时被破坏 是的,他们工作正常,但是……

但是实际上,一切都简单得多,因为Android已经为您完成了!

如果您仔细看一下 在RecyclerView / ListView / ScrollView / NestedScrollView源中,您将看到每个源都将其滚动位置保存在onSaveInstanceState中。并且在第一次布局传递期间,他们正尝试在onLayout方法中滚动到该位置。

只需要做两件事,以确保它可以正常运行:

  1. 为您的可滚动视图设置ID,这可能已经完成。否则,Android将无法自动保存视图状态。

  2. 在第一次布局通过之前提供数据,以具有与旋转之前相同的滚动边界。这是开发人员通常遇到一些问题的步骤。

答案 6 :(得分:0)

我发现的最简单且与过渡兼容的方法是:

   @Override
public void onPause() {
    super.onPause();
    recyclerView.setLayoutFrozen(true);
}

@Override
public void onResume() {
    super.onResume();
    recyclerView.setLayoutFrozen(false);
}

答案 7 :(得分:-1)

您可以使用scrollToPositionsmoothScrollToPosition滚动到RecyclerView 中的任何项目位置。

如果要滚动到适配器中的项目位置,则必须使用适配器scrollToPositionsmoothScrollToPosition