簡體   English   中英

如何維護屏幕旋轉的recyclerView的Scroll position

[英]How to Maintain Scroll position of recyclerView on Screen Rotation

我正在使用 gridlayoutManager 填充 recyclerView。 現在我想在屏幕旋轉時保存滾動條 position。

我嘗試使用 onSaveInstanceState 和 onRestoreInstanceState() 來這樣做,如本文所示:

如何使用 RecyclerView.State 保存 RecyclerView 的滾動條 position?

下面是我的代碼:

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

這是這個項目 GitHub 的鏈接https://github.com/harshabhadra/Movies-Mela

現在,它有簡單的解決方案。使用此依賴項

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

然后像下面一樣設置 stateRestorationPolicy

myAdapter.stateRestorationPolicy=RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

我知道我遲到了,但如果有幫助的話!

存儲回收站視圖位置比其他答案看起來簡單得多

這是你可以做到的方法

首先創建一個成員變量

    Parcelable state;

現在,

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

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

使用上述代碼覆蓋暫停和恢復方法,您就可以開始了!!

一種方法是停止重新創建有關方向變化的活動。 您可以將其添加到清單中的活動中。

android:configChanges="orientation|screenSize"

但這並不總是一個好的做法,因此另一種替代方法是在退出onSaveInstanceState之前保存適配器位置,然后使用scrollToPositiononCreate滾動到該位置。 因此,例如,您可以按照以下方式做一些事情。

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

你應該看看這個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];
            }
        };
    }
}

實現您想要獲得的最簡單方法是在 Fragment 中使用 RecyclerView 而不是直接在 Activity 中使用。

與活動不同,默認情況下片段不會在旋轉時重新創建,而是保留它們的狀態。 這樣,recyclerview 將始終保持在相同的滾動位置。

我在我的一個應用程序中以這種方式使用 RecyclerView,它顯示具有 > 200 個元素的列表。

如果您使用GridLayoutManager ,它應該已經自動保存滾動位置,它是LinearLayoutManager子類。 您可以在LinearLayoutManager查看SavedState

public static class SavedState implements Parcelable {

    int mAnchorPosition;

    int mAnchorOffset;

    boolean mAnchorLayoutFromEnd;

mAnchorPosition是您的滾動位置,並在旋轉期間保存。 如果這對您不起作用,則可能有其他問題:例如,您可能錯誤地重新加載/重新應用數據。 這可能是您需要提出的真正問題。 您可能需要將該數據緩存在某處,以便您可以在配置更改后立即自動重新應用它。

我還可以確認在我使用LinearLayoutManagerGridLayoutManager每個項目上的價值,在旋轉期間正確保持滾動位置,我沒有額外的工作。

我已經嘗試了每個人建議的所有內容,但最后,這個要點對我有用

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

我只是在我的項目中導入它並用這個“StateFulRecyclerView”替換默認提供的recyclerView,它解決了我的問題並在屏幕旋轉或任何配置更改期間自動處理滾動位置。 無需使用 onSaveInstanceState 來維護滾動位置。

很簡單。 在暫停和恢復時保存位置。

暫停

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

在簡歷上

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

或者

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

一種解決方案是通過保存 recycleview 的滾動位置

在片段的onSaveInstanceState()方法中,您可以保存 RecycleView 的滾動條 position

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

然后你可以在onViewStateRestored()方法中檢索保存的滾動 position

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM