【问题标题】:Save scroll state in nested RecyclerView在嵌套的 RecyclerView 中保存滚动状态
【发布时间】:2025-11-28 13:30:02
【问题描述】:

我的申请有问题。我有主列表(回收站视图)。此列表保留 20 个水平回收站视图。它看起来非常像 Netflix 应用程序。我需要保持主列表中每个“轮播”的状态。如果我将第一个项目向右、向左移动、向下滚动(第一个和第二个项目被回收)、旋转屏幕、向上滚动,我需要恢复第一个和第二个元素的位置。

我知道我应该使用 linearLayout.saveOnInstanceState 和 onRestoreState 但我的问题是每个轮播都在主列表中。

AndroidManifest.xml 中的configChanges 无法发挥作用...

谢谢!

【问题讨论】:

标签: android android-layout android-recyclerview android-view android-scrollview


【解决方案1】:

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

【讨论】:

  • 我不知道为什么,但我只能保存一次状态。然后价值永远不会改变。它始终是相同的滚动偏移量。你碰巧知道为什么?
【解决方案2】:

您可以在 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);
    }
}

您唯一需要注意的是,您不希望父适配器在方向更改后被销毁和创建,使其在方向更改后仍然存在。否则将int[] 保存到Bundle,然后从onRestoreInstanceState() 取回。

【讨论】:

  • 好的,你的回答很有道理。即使 os 通过视图杀死活动,我也可以从 bundle 中恢复 int[] :)
  • scrollX / getScrollX() 来自(是的,水平滚动)回收站视图始终为 0。
  • @Ixx,这很奇怪。
  • 我认为我们必须使用computeHorizontalScrollOffset()
【解决方案3】:

这是我实施的解决方案:

1:使用布局管理器通过recyclerView.layoutmanager.findLastVisibleItemPosition()找到lastVisible元素

  1. 使用接口将此值发送到您的调用活动或片段

  2. 将此值存储在 hashmap 中并将其传递给外部 recyclerViewAdapter

  3. 将其传递给内部 recyclerViewAdapter 以将其更新到使用 recyclerview.scrollToPosition[hashmapofpositions[YOUR_KEY]] 存储的位置

这样,您在上次运行中使用的状态就会得到保存。

【讨论】:

    最近更新 更多