简体   繁体   English

在嵌套的 RecyclerView 中保存滚动状态

[英]Save scroll state in nested RecyclerView

I have a problem in my application.我的应用程序有问题。 I have main list (recycler view).我有主列表(回收商视图)。 This list keeps 20 horizontal recycler views.此列表保留 20 个水平回收器视图。 It looks really similar like Netflix app.它看起来非常像 Netflix 应用程序。 I need to keep state of every "carousel" in main list.我需要在主列表中保留每个“轮播”的状态。 If I move first item to right, next to left, scroll down (first and second items are recycled), rotate the screen, scroll up, I need to have restored position of first and second element.如果我将第一项向右移动,向左移动,向下滚动(第一项和第二项被回收),旋转屏幕,向上滚动,我需要恢复第一个和第二个元素的位置。

I know that I should use linearLayout.saveOnInstanceState and onRestoreState but my problem is that every carousel is in main list.我知道我应该使用 linearLayout.saveOnInstanceState 和 onRestoreState 但我的问题是每个轮播都在主列表中。

configChanges in AndroidManifest.xml can not come into play... AndroidManifest.xml 中的configChanges无法发挥作用...

Thank you!谢谢!

As @Ixx mentioned scrollX is always 0. You have to use layoutManager to save and restore scroll position正如@Ixx 提到的,scrollX 始终为 0。您必须使用 layoutManager 来保存和恢复滚动位置

 val scrollStates = mutableMapOf<Int, Parcelable?>()
override fun onViewRecycled(holder: VH) {
    super.onViewRecycled(holder)

    val key = holder.layoutPosition
    scrollStates[key] = holder.childRecycler.layoutManager.onSaveInstanceState()
}

override fun onBindViewHolder(holder: VH, position: Int) {
    val key = holder.layoutPosition
    val state = scrollStates[key]
    if(state != null){
        holder.childRecycler.layoutManager.onRestoreInstanceState(state)
    }else{

        holder.childRecycler.layoutManager.scrollToPosition(0)
    }
}

You can save scrollX position when you item of RecyclerView is being recycled, and then scroll that much when that item is being bind again:您可以在RecyclerView项目时保存scrollX位置,然后在再次绑定该项目时滚动那么多:

int[] scrollXState = new int[20]; // assuming there are 20 carousel items

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    // setup recycler here, then post scrollX after recycler has been laid out
    holder.nestedRecyclerView.post(() ->
            holder.nestedRecyclerView.setScrollX(scrollXState[holder.getAdapterPosition()]));
}

@Override
public void onViewRecycled(MyViewHolder holder) {
    scrollXState[holder.getAdapterPosition()] = holder.nestedRecyclerView.getScrollX();
    super.onViewRecycled(holder);
}

class MyViewHolder extends RecyclerView.ViewHolder {

    RecyclerView nestedRecyclerView;

    public MyViewHolder(View itemView) {
        super(itemView);
    }
}

Only thing you should take care of is that you do not want parent adapter to be destroyed and created after orientation change, make it survive orientation change.您唯一应该注意的是,您不希望在方向更改后销毁和创建父适配器,使其在方向更改后继续存在。 Otherwise save int[] into Bundle and then get it back from onRestoreInstanceState() .否则将int[]保存到Bundle ,然后从onRestoreInstanceState()

This is the solution i implemented:这是我实施的解决方案:

1:Use layout manager to find the lastVisible element by using recyclerView.layoutmanager.findLastVisibleItemPosition() 1:使用布局管理器通过recyclerView.layoutmanager.findLastVisibleItemPosition()找到lastVisible元素

  1. use an interface to send this value to your calling activity or fragment使用接口将此值发送到您的调用活动或片段

  2. store this value in a hashmap and pass it to the outer recyclerViewAdapter将此值存储在哈希图中并将其传递给外部 recyclerViewAdapter

  3. pass it to the inner recyclerViewAdapter to update it to the position stored by using recyclerview.scrollToPosition[hashmapofpositions[YOUR_KEY]]将其传递给内部 recyclerViewAdapter 以将其更新为使用recyclerview.scrollToPosition[hashmapofpositions[YOUR_KEY]]存储的位置

This way your state that you used in the last run is conserved.这样,您在上次运行中使用的状态就会得到保存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM