提问者:小点点

恢复屏幕方向上的回收视图滚动位置android


我有一个从服务器加载数据的回收视图。它有一个GridLayout作为它的layoutmanager。在屏幕方向上,我想保留回收视图的滚动位置。我尝试了堆栈溢出的许多解决方案。但它并不完美。我的意思是“不完美地工作”,它在多次屏幕方向后没有保留正确的滚动位置。这是我的代码实现:

onSaveInstanceStateonRestoreInstanceState

@Override
    protected void onSaveInstanceState(Bundle outState) {
        listState = recyclerView.getLayoutManager().onSaveInstanceState();
        outState.putParcelable(Constants.POSITION, listState);
        super.onSaveInstanceState(outState);
    }


    protected void onRestoreInstanceState(Bundle state) {
        // Retrieve list state and list/item positions
        if (state != null) {
            listState = state.getParcelable(Constants.POSITION);
            Log.e(TAG, "list state not null");
        }
        super.onRestoreInstanceState(state);
    }

    private void restoreState() {
        Log.e(TAG, "restoreStated called");
        if (listState != null) {
            recyclerView.getLayoutManager().onRestoreInstanceState(listState);
            listState = null;
        }
    }

设置数据后调用恢复状态:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        ((MyApplication) getApplication()).getComponent().inject(this);
        movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);
        recyclerView.setHasFixedSize(true);
        gridLayoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(gridLayoutManager);
        adapter = new MovieListAdapter(MainActivity.this);
        recyclerView.setAdapter(adapter);
        movieListViewModel.getMovieList();
        observePopularMovieList();

    }

private void observePopularMovieList() {
        movieListViewModel.result.observe(this, new Observer<NetworkResponse>() {
            @Override
            public void onChanged(@Nullable NetworkResponse networkResponse) {
                if (networkResponse.getPostData() != null) {
                    movieData = networkResponse.getPostData();
                    adapter.addData(movieData.getResults());
                    Handler handler = new Handler();
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            restoreState();
                        }
                    },50);
                } else {
                    Log.e(TAG, "failure");
                }
            }
        });
    }

共3个答案

匿名用户

如果您在活动中有回收器视图,请尝试将回收器ViewAdapter保存在活动的ViewModel中,并在方向更改时获取适配器并将其设置为回收器视图。

如果你在一个片段中有回收视图,那么尝试在方向改变时获得相同的片段

片段保存片段=getSupportFragmentManager(). findFragmentByTag("Fragment_having_recyclerview");

然后设置这个片段,而不是创建同一个片段的新实例

匿名用户

您应该使用savedInstanceBundle而不是将其保存在某个变量中,因为当屏幕方向发生变化时,活动将被销毁并重新创建,因此您的所有活动状态都将被销毁并重新创建。

 @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      savedInstanceState.putInt("pos", mRecyclerView.getAdapterPosition()); // gives current recycle view position.
      super.onSaveInstanceState(savedInstanceState);
    }

然后在onCreate()中可以得到这样的位置。

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

        setContentView(R.layout.activity_main);
        ..
        ..
        mRecyclerView.setAdapter(mRecyclerAdapter);
        if(savedInstanceState != null){
          mRecyclerView.post(new Runnable() {
            @Override
            public void run() {
                int pos = savedInstanceState.getInt("pos");
                mRecyclerView.scrollToPosition(pos);     
            }
        });

      }  

}

在Adapter类中创建getAdapterPopse(),如下所示。

private class ComponentRecycleAdapter extends RecyclerView.Adapter<ComponentHolder> {

  ComponentHoder myHolder = null;

        @Override
        public ComponentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.one_component_item_list, parent, false);
            return new ComponentHolder(view);
        }

        @Override
        public void onBindViewHolder(ComponentHolder holder, int position) {
            ..
            ..
            ..
            this.myHolder  = holder;
        }

        @Override
        public int getItemCount() {
                ..
        }
        public int getAdapterPosition(){
           return myHolder =! null ? myHolder.getAdapterPosition() : 0;
        }
    }

让我知道它是否有效。快乐编码:)

匿名用户

在尝试了很多解决方案后,这帮助我准确地恢复了回收视图的位置

  @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
            if (newConfig.orientation == SCREEN_ORIENTATION_LANDSCAPE || newConfig.orientation == SCREEN_ORIENTATION_USER) {            
                if(mRecyclerView!=null && mRecyclerView.getLayoutManager()!=null) {
                    mBundleRecyclerViewState = new Bundle();
                    mListState = mRecyclerView.getLayoutManager().onSaveInstanceState();
                    mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);
                }

            } else if (newConfig.orientation == SCREEN_ORIENTATION_PORTRAIT) {
                if (mBundleRecyclerViewState != null) {
                    new Handler().postDelayed(() -> {
                        if(mRecyclerView!=null && mRecyclerView.getLayoutManager()!=null) {
                            mListState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
                            mRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);
                        }

                    }, 100);
                }

            }
    }