如何在ListAdapter<T, VH>中实现嵌套RecyclerView
使用ListAdapter实现嵌套RecyclerView完全可行
ListAdapter是RecyclerView.Adapter的子类,天然支持嵌套场景,核心是分别为父、子RecyclerView实现对应的ListAdapter,并在父ViewHolder中完成子RecyclerView的配置与数据绑定。以下是具体实现步骤:
1. 定义嵌套数据结构
先明确父项和子项的数据模型:
// 子项数据类,存储单个子项内容 data class ChildItem(val name: String) // 父项数据类,包含父项标题和对应的子项列表 data class ParentItem(val title: String, val childItems: List<ChildItem>)
2. 实现子ListAdapter
负责渲染父项中嵌套的子RecyclerView,核心是实现DiffCallback以支持高效数据更新:
class ChildAdapter : ListAdapter<ChildItem, ChildAdapter.ChildViewHolder>(DiffCallback()) { inner class ChildViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val tvChildName: TextView = itemView.findViewById(R.id.child_item_name) // 替换为你的子项布局中的TextView ID fun bind(childItem: ChildItem) { tvChildName.text = childItem.name } } // 实现DiffCallback判断数据变化 class DiffCallback : DiffUtil.ItemCallback<ChildItem>() { override fun areItemsTheSame(oldItem: ChildItem, newItem: ChildItem): Boolean { // 根据业务唯一标识判断是否为同一子项 return oldItem.name == newItem.name } override fun areContentsTheSame(oldItem: ChildItem, newItem: ChildItem): Boolean { // 判断内容是否一致 return oldItem == newItem } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChildViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_child, parent, false) // 替换为你的子项布局文件 return ChildViewHolder(view) } override fun onBindViewHolder(holder: ChildViewHolder, position: Int) { holder.bind(getItem(position)) } }
3. 实现父ListAdapter
父Adapter需要在ViewHolder中初始化子RecyclerView,并绑定子Adapter的数据:
class ParentAdapter : ListAdapter<ParentItem, ParentAdapter.ParentViewHolder>(DiffCallback()) { inner class ParentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val tvParentTitle: TextView = itemView.findViewById(R.id.content_title) private val childRecyclerView: RecyclerView = itemView.findViewById(R.id.child_recycler_view) private val childAdapter = ChildAdapter() init { // 配置子RecyclerView的布局管理器(示例为横向布局,可根据需求改为纵向) childRecyclerView.layoutManager = LinearLayoutManager(itemView.context, LinearLayoutManager.HORIZONTAL, false) childRecyclerView.adapter = childAdapter // 禁用子RecyclerView的嵌套滑动,适配外层NestedScrollView childRecyclerView.isNestedScrollingEnabled = false } fun bind(parentItem: ParentItem) { tvParentTitle.text = parentItem.title // 提交子项数据到子Adapter childAdapter.submitList(parentItem.childItems) } } // 父项的DiffCallback实现 class DiffCallback : DiffUtil.ItemCallback<ParentItem>() { override fun areItemsTheSame(oldItem: ParentItem, newItem: ParentItem): Boolean { return oldItem.title == newItem.title } override fun areContentsTheSame(oldItem: ParentItem, newItem: ParentItem): Boolean { return oldItem == newItem } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParentViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_row_parent, parent, false) return ParentViewHolder(view) } override fun onBindViewHolder(holder: ParentViewHolder, position: Int) { holder.bind(getItem(position)) } }
4. 在主Activity中配置父RecyclerView
完成父RecyclerView的布局管理器、Adapter绑定,并提交测试数据:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val parentRecyclerView = findViewById<RecyclerView>(R.id.parent_recycler_view) val parentAdapter = ParentAdapter() // 配置父RecyclerView的布局管理器 parentRecyclerView.layoutManager = LinearLayoutManager(this) parentRecyclerView.adapter = parentAdapter // 禁用父RecyclerView的嵌套滑动,避免与外层NestedScrollView冲突 parentRecyclerView.isNestedScrollingEnabled = false // 构造测试数据 val testData = listOf( ParentItem( title = "House of Stark", childItems = listOf(ChildItem("Robb"), ChildItem("Sansa"), ChildItem("Arya"), ChildItem("Bran"), ChildItem("Rickon")) ), ParentItem( title = "House of Lannister", childItems = listOf(ChildItem("Tywin"), ChildItem("Cersei"), ChildItem("Jaime"), ChildItem("Tyrion")) ) ) // 提交数据到父Adapter parentAdapter.submitList(testData) } }
关键注意点
- DiffCallback正确性:
areItemsTheSame要基于数据的唯一标识判断,areContentsTheSame要确保内容完全一致,否则ListAdapter无法正确更新UI。 - 嵌套滑动优化:外层使用NestedScrollView时,必须将父、子RecyclerView的
isNestedScrollingEnabled设为false,否则会出现滑动卡顿或滚动冲突。 - Adapter复用:子Adapter在父ViewHolder的
init块中初始化,不要在bind方法中重复创建,避免不必要的性能开销。
内容的提问来源于stack exchange,提问作者Abhishek Charismatic
相关产品推荐
相关产品推荐

