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

Def*_*XYZ 18 android scroll android-recyclerview

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

是的,我用Google搜索,在StackOverFlow中找到关于保存布局管理器实例的文章,如下所示:RecyclerView在活动之间存储/恢复状态.但是,它对我没有帮助.

UPDATE

现在我有这种解决问题,当然,它也没有用.

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();
}
Run Code Online (Sandbox Code Playgroud)

是的,我尝试过scrollTo(int,int) - 不行.

现在我尝试滚动,例如,Y = 100,但它根本不滚动.

Mad*_*bar 43

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

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

恢复滚动位置@onResume:

    if (positionIndex!= -1) {
        llManager.scrollToPositionWithOffset(positionIndex, topView);
    }
Run Code Online (Sandbox Code Playgroud)

或者其他方式可以是@onPause:

long currentVisiblePosition = 0;
currentVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
Run Code Online (Sandbox Code Playgroud)

恢复@onResume:

((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(currentVisiblePosition);
currentVisiblePosition = 0;
Run Code Online (Sandbox Code Playgroud)


Kuf*_*ffs 20

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

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

}
Run Code Online (Sandbox Code Playgroud)

然后打电话

list.getLayoutManager().onRestoreInstanceState(listState);
Run Code Online (Sandbox Code Playgroud)

一旦您的数据重新附加到您的数据 RecyclerView

  • 哇!简单易用的解决方案:) (3认同)
  • 我认为这是最好的解决方案! (2认同)
  • @LeonardoAssunção 那你做错了。这不是必需的,也不推荐。 (2认同)
  • 由于我使用的是片段,因此我在`onDestroyView()`而不是`onStop()`中有上面的代码行。@Kuffs,你的提示与这个解决方案相结合确实解决了我的问题。谢谢! (2认同)
  • 你好,我们可以在哪里调用这个方法 list.getLayoutManager().onRestoreInstanceState(listState); (2认同)

Rub*_*era 5

从 androidx recyclerView 库的 1.2.0-alpha02 版本开始,现在是自动管理的。只需添加它:

implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
Run Code Online (Sandbox Code Playgroud)

并使用:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
Run Code Online (Sandbox Code Playgroud)

StateRestorationPolicy 枚举有 3 个选项:

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

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