RecyclerView 嵌套 RecyclerView 如何保存位置

首先, 我们给 外部的 recyclerView 命名为 outer, 内部的 recyclerView 命名为 inner

问题是这样的: 布局是 outer 的一个 item 是 inner, inner 横向可滑动的, 上下滑动后, 回到 inner 位置, 发现 inner 又回到了初始位置, 如下图:

直接给结论:

1. inner 在 outer onBind 时, 不要重复设置 layoutManager, 如果非必要也不要让 adapter 刷新, recyclerView 有自己的回收复用机制, inner 会正常保留滑动的位置.

2. 如果 inner 滑动回来时需要更新 adapter, 可以使用 inner.post, 在 post 中更新 adapter 数据, 这样 inner 仍会保留之前的位置.

 

正确代码示例:

上图可见, inner 的 adapte 只会在 outer 的 viewholder(LiveAttentionBannerVH) 中初始化一次, 在执行 onBindBanner 时, inner 也只会设置一次 adapter.

因为本人菜鸡, 不会看源码, 所以只能猜测一下...

原因猜想:

1. 重新设置 layoutManager 会重新布局, recyclerView 就回到了初始位置.

2. 滑动后让 inner 重新展示时, inner 首先会让 itemView 执行 attach, 此时让 adapter 刷新数据, 因为 view 还没有重新排列好, adapter 刷新就会覆盖掉之前的位置, 导致位置无法记录, post 有效原因也在于此, 因为会在下一个消息循环中刷新, view 就保留在上次的位置进行刷新数据了.

以上纯属猜想, 又遇到问题的小伙伴可以先试着解决下.

后续会努力看下 recyclerView 的源码, 在开发中实在是了解其真正的原理实在太重要了, 最近在 recyclerView 上踩了不少坑... o(╥﹏╥)o

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RecyclerView 嵌套 RecyclerView 可以用来实现一些复杂的列表布局,比如类似于网格布局的效果。实现的方法可以分为两种:使用 RecyclerView.Adapter 实现和使用 RecyclerView.LayoutManager 实现。 1. 使用 RecyclerView.Adapter 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 Adapter 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 Adapter 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerAdapter> innerAdapters; public void setInnerAdapters(List<InnerAdapter> innerAdapters) { this.innerAdapters = innerAdapters; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setAdapter(innerAdapters.get(position)); } @Override public int getItemCount() { return innerAdapters.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); innerRecyclerView.setLayoutManager(new LinearLayoutManager(itemView.getContext(), RecyclerView.HORIZONTAL, false)); } } } ``` 在内层 RecyclerView 的 Adapter 中,需要重写 onCreateViewHolder 方法,创建内层 RecyclerViewViewHolder,同时需要重写 onBindViewHolder 方法,将数据绑定到内层 RecyclerViewViewHolder 上。 ```java public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.InnerViewHolder> { private List<String> data; public void setData(List<String> data) { this.data = data; } @NonNull @Override public InnerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_inner, parent, false); return new InnerViewHolder(view); } @Override public void onBindViewHolder(@NonNull InnerViewHolder holder, int position) { holder.textView.setText(data.get(position)); } @Override public int getItemCount() { return data.size(); } static class InnerViewHolder extends RecyclerView.ViewHolder { TextView textView; public InnerViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ``` 2. 使用 RecyclerView.LayoutManager 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 LayoutManager 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 LayoutManager 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerLayoutManager> innerLayoutManagers; public void setInnerLayoutManagers(List<InnerLayoutManager> innerLayoutManagers) { this.innerLayoutManagers = innerLayoutManagers; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setLayoutManager(innerLayoutManagers.get(position)); } @Override public int getItemCount() { return innerLayoutManagers.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); } } } ``` 在内层 RecyclerView 的 LayoutManager 中,需要重写 generateDefaultLayoutParams 方法,设置内层 RecyclerView 的布局参数,同时需要重写 canScrollHorizontally 和 canScrollVertically 方法,判断内层 RecyclerView 是否可以滑动。 ```java public class InnerLayoutManager extends LinearLayoutManager { public InnerLayoutManager(Context context) { super(context); } @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override public boolean canScrollHorizontally() { return false; } @Override public boolean canScrollVertically() { return false; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃饱很舒服

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值