如何在屏幕旋转时保持RecyclerView的滚动位置

时间:2019-07-16 16:03:56

标签: java android android-recyclerview gridlayoutmanager

我正在用gridlayoutManager填充recyclerView。现在,我想在屏幕旋转上保存滚动位置。

我尝试使用onSaveInstanceState和onRestoreInstanceState()这样做 下面是我的代码:

@Override
protected void onSaveInstanceState(Bundle outState) {
    Log.e(TAG, "onSaveInstanceState");
    super.onSaveInstanceState(outState);
    outState.putParcelable(KEY_INSTANCE_STATE_RV_POSITION, 
    gridLayoutManager.onSaveInstanceState());
 }


@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {

    Log.e(TAG, "onRestoreInstanceState");
    super.onRestoreInstanceState(savedInstanceState);
    if (savedInstanceState!= null){
        Parcelable savedState = 
    savedInstanceState.getParcelable(KEY_INSTANCE_STATE_RV_POSITION);

        movieAdapter.addAll(movieItemList);
        if (savedState!= null){
            gridLayoutManager.onRestoreInstanceState(savedState);
        }
    }
}


//this is my movieAdapter.addAll() method 

public void addAll(List<MovieItem>items){

    movieItems = items;
}


//This is the method to get lists of movies from ViewModel Class

private void loadFavMovies() {
    FavViewModel favViewModel = 
    ViewModelProviders.of(MainActivity.this).get(FavViewModel.class);
    favViewModel.getFavListLiveData().observe(MainActivity.this, new 
    Observer<List<FavlistItem>>() {
        @Override
        public void onChanged(List<FavlistItem> favlistItems) {
            if (!favlistItems.isEmpty()) {
                loadingIndicator.setVisibility(View.GONE);
                movieRecycler.setVisibility(View.GONE);
                favRecycler.setVisibility(View.VISIBLE);
                favAdapter.setFavlistItems(favlistItems);
                Toast.makeText(getApplicationContext(), "Swipe Left Or 
       Right To remove Item",Toast.LENGTH_SHORT).show();
               }else {
                loadingIndicator.setVisibility(View.GONE);
                Toast.makeText(getApplicationContext(), "No Favorite 
      Movies",Toast.LENGTH_SHORT).show();
            }
        }
    });
}

这是此项目https://github.com/harshabhadra/Movies-Mela的GitHub链接

7 个答案:

答案 0 :(得分:3)

我知道我迟到了,但如果它有帮助的话!

存储回收站视图位置比其他答案看起来要简单得多

你可以这样做

先创建一个成员变量

    Parcelable state;

现在

@Override
protected void onPause() {
    super.onPause();
    state = recyclerView.getLayoutManager().onSaveInstanceState();
}

@Override
protected void onResume() {
    super.onResume();
        recyclerView.getLayoutManager().onRestoreInstanceState(state);
}

使用上面的代码覆盖暂停和恢复方法,你就可以开始了!!

答案 1 :(得分:2)

现在,它有简单的解决方案。使用此依赖项

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

然后像下面一样设置stateRestorationPolicy

myAdapter.stateRestorationPolicy=RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

答案 2 :(得分:1)

做到这一点的一种方法是停止在方向改变时重新创造活动。您可以将其添加到清单中的活动中。

android:configChanges="orientation|screenSize"

但这并不总是一个好习惯,因此另一种选择是保存适配器位置,然后退出onSaveInstanceState,然后使用onCreate滚动到scrollToPosition中的位置。因此,例如,您将按照以下方式进行操作。

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      savedInstanceState.putInt("position", mRecyclerView.getAdapterPosition()); // get current recycle view position here.
      //your other code
      super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      //your other code
      if(savedInstanceState != null){
        // scroll to existing position which exist before rotation.

  mRecyclerView.scrollToPosition(savedInstanceState.getInt("position"));
      }
   }

答案 3 :(得分:0)

实现您想要获得的最简单的方法是在Fragment中而不是直接在Activity中使用RecyclerView。

与活动不同,默认情况下,片段不会在旋转时重新创建,但会保留其状态。这样,recyclerview将始终保持在相同的滚动位置。

我正在其中一个应用程序中以这种方式使用RecyclerView,该应用程序显示包含200多个元素的列表。

答案 4 :(得分:0)

如果您使用0的子类GridLayoutManager,则滚动位置应该已经自动保存。您可以查看LinearLayoutManager内的SavedState

LinearLayoutManager

public static class SavedState implements Parcelable { int mAnchorPosition; int mAnchorOffset; boolean mAnchorLayoutFromEnd; 实际上是您的滚动位置,并且在旋转过程中已保存。如果这对您不起作用,则可能是其他原因:例如,您可能错误地重新加载/重新应用了数据。这可能是您需要提出的真正问题。您可能需要将该数据缓存在某处,以便在配置更改后立即自动重新应用。

我还可以确认在我使用过mAnchorPositionLinearLayoutManager的每个项目中有什么价值,在旋转过程中可以正确保持滚动位置,而无需我做任何额外的工作。

答案 5 :(得分:0)

我已经尝试了所有人提出的所有建议,但是最后,这项要点对我来说有用

https://gist.github.com/FrantisekGazo/a9cc4e18cee42199a287

我只是将其导入到我的项目中,并用此替换默认提供的recyclerView “ StateFulRecyclerView”解决了我的问题,并在屏幕旋转或任何配置更改期间自动处理滚动位置。无需使用onSaveInstanceState来维护滚动位置。

答案 6 :(得分:0)

很简单。保存暂停时的位置,恢复时恢复。

ON 暂停

lastVisitPosition = ((LinearLayoutManager)recycleView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

onResume

((LinearLayoutManager) recycleView.getLayoutManager()).scrollToPosition(lastVisitPosition);

((LinearLayoutManager) recycleView.getLayoutManager()).scrollToPositionWithOffset(lastVisitPosition,0)