android 屏幕旋转时如何保持recyclerView的滚动位置

nzkunb0c  于 2023-01-24  发布在  Android
关注(0)|答案(9)|浏览(279)

我正在用gridlayoutManager填充recyclerView。现在我想保存屏幕旋转的滚动位置。
我试过使用onSaveInstanceState和onRestoreInstanceState()来实现这一点,如本文所示:
How to save RecyclerView's scroll position using RecyclerView.State?
下面是我的代码:

@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的链接

ru9i0ody

ru9i0ody1#

现在,它有简单的解决方案.使用这个依赖项

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

只需如下所示设置stateRestorationPolicy

myAdapter.stateRestorationPolicy=RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY
ebdffaop

ebdffaop2#

我知道我迟到了,但如果有帮助的话!!
存储回收器视图位置要比其他答案使其看起来简单得多
以下是您的操作方法
首先创建成员变量

Parcelable state;

现在,

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

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

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

vs3odd8k

vs3odd8k3#

一种方法是在方向改变时停止重新创建活动,您可以将其添加到清单中的活动中来完成此操作。

android:configChanges="orientation|screenSize"

但这并不总是一个好的做法,因此另一种替代方法是在onSaveInstanceState中退出之前保存适配器位置,然后使用scrollToPosition滚动到onCreate中的该位置。

@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"));
      }
   }
von4xj4u

von4xj4u4#

如果你使用GridLayoutManager,它是LinearLayoutManager的子类,滚动位置应该已经自动保存了。你可以看看LinearLayoutManager里面的SavedState

public static class SavedState implements Parcelable {

    int mAnchorPosition;

    int mAnchorOffset;

    boolean mAnchorLayoutFromEnd;

mAnchorPosition实际上就是你的滚动位置,它在旋转过程中会被保存。如果这对你不起作用,很可能是其他地方出了问题:例如,你可能不正确地重新加载/重新应用数据。2这可能是你真实的需要问的问题。3你可能需要在某个地方缓存这些数据,这样你就可以在配置改变后立即自动地重新应用它。
我还可以确认它的价值,在每一个项目上,我已经使用LinearLayoutManagerGridLayoutManager,滚动位置是正确的保持在旋转过程中,没有额外的工作对我的一部分。

vcirk6k6

vcirk6k65#

你应该看看这个SO post
基本上,你想创建一个扩展RecyclerView的新类(记住你必须使用你的新类而不是RecyclerView),并覆盖onSaveInstanceState()onRestoreInstanceState(),在onSaveInstanceState()中你将保存第一个可见元素的索引,并在onRestoreInstanceState()中滚动到那个元素。
他们在链接帖子的可接受答案中使用的方法不同,而是使用LinearLayoutManager,因此我将调整代码以使用GridLayoutManager

public class CustomRecyclerView extends RecyclerView {
    private int mScrollPosition;
    public VacationsRecyclerView(@NonNull Context context) {
        super(context);
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(state);
        if(state != null && state instanceof SavedState){
            mScrollPosition = ((SavedState) state).mScrollPosition;
            LayoutManager layoutManager = getLayoutManager();
            if(layoutManager != null){
                int count = layoutManager.getItemCount();
                if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
                    layoutManager.scrollToPosition(mScrollPosition);
                }
            }
        }
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        LayoutManager layoutManager = getLayoutManager();
        if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
            mScrollPosition = ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition();
        }
        SavedState newState = new SavedState(superState);
        newState.mScrollPosition = mScrollPosition;
        return newState;
    }

    static class SavedState extends android.view.View.BaseSavedState {
        public int mScrollPosition;
        SavedState(Parcel in) {
            super(in);
            mScrollPosition = in.readInt();
        }
        SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(mScrollPosition);
        }
        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}
twh00eeo

twh00eeo6#

要实现您想要的目标,最简单的方法是在Fragment中使用RecyclerView,而不是直接在Activity中使用。
与Activity不同,默认情况下片段不会在旋转时重新创建,而是保留它们的状态,这样,recyclerview将始终保持在相同的滚动位置。
我在我的一个应用程序中以这种方式使用RecyclerView,它显示的列表包含超过200个元素。

3zwtqj6y

3zwtqj6y7#

每个人建议的我都试过了,但最后,这个要点对我有用
https://gist.github.com/FrantisekGazo/a9cc4e18cee42199a287
我只是将其导入到我的项目中,并将默认提供的recyclerView替换为“StateFulRecyclerView”,它解决了我的问题,并在屏幕旋转或任何配置更改期间自动处理滚动位置。无需使用onSaveInstanceState来维护滚动位置。

6gpjuf90

6gpjuf908#

非常简单,保存暂停位置,恢复恢复位置。
ON暂停

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

关于恢复

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

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

p5fdfcr19#

一种解决方案是保存recycleview的滚动位置
在片段的**onSaveInstanceState()**方法中可以保存RecycleView的滚动位置

@Override
  public void onSaveInstanceState(Bundle outState) {
   super.onSaveInstanceState(outState);
   LinearLayoutManager layoutManager = (LinearLayoutManager) 
   recyclerView.getLayoutManager();
   outState.putInt("scrolled_position", 
   layoutManager.findFirstCompletelyVisibleItemPosition());
}

然后可以在**onViewStateRestored()**方法中检索保存的滚动位置

@Override
  public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
  super.onViewStateRestored(savedInstanceState);
  if (savedInstanceState != null) {
    int scrollPosition = savedInstanceState.getInt("scrolled_position");
    recyclerView.scrollToPosition(scrollPosition);
  }
}

相关问题