如何为不同Fragment的RecyclerView复用同一Adapter(不同布局)?
当然可行!无需复制Adapter就能实现不同布局复用
完全没必要复制Adapter类,我们只需要给MainMarkAdapter添加一个简单的配置,就能让它适配不同Fragment里的RecyclerView布局需求~
步骤1:修改Adapter构造函数,传入布局ID
首先给Adapter的构造函数新增一个参数,用来接收当前RecyclerView需要使用的Item布局ID:
MainMarkAdapter( private val activity: MainActivity, private var listOfData: ArrayList<MainMarkModling>, val listener: ContentListener, private val itemLayoutId: Int // 新增:传入目标布局ID ) : RecyclerView.Adapter<MainMarkAdapter.ViewHolder>() {
步骤2:在onCreateViewHolder中使用传入的布局ID
修改onCreateViewHolder方法,不再硬编码布局ID,而是用我们传入的itemLayoutId来填充布局:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(itemLayoutId, parent, false) return ViewHolder(view) }
步骤3:适配不同布局的ViewHolder(关键)
如果两个布局的控件结构不同(比如控件ID、数量不一样),我们需要让ViewHolder兼容两种布局,这里推荐两种常用方式:
方式一:基于View的通用适配(适合布局差异小的情况)
如果只是部分控件ID不同,可以在ViewHolder里根据布局类型初始化控件:
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // 根据布局ID获取对应的标题TextView val titleTv: TextView = when(itemLayoutId) { R.layout.item_layout_fragment1 -> itemView.findViewById(R.id.tv_frag1_title) R.layout.item_layout_fragment2 -> itemView.findViewById(R.id.tv_frag2_title) else -> throw IllegalArgumentException("不支持的布局ID") } // 其他控件同理处理 }
方式二:基于ViewBinding的优雅适配(推荐)
如果布局差异较大,用ViewBinding会更清晰。先确保你已经开启了ViewBinding,然后为两个布局生成对应的Binding类(比如ItemLayoutFragment1Binding和ItemLayoutFragment2Binding),再修改ViewHolder:
class ViewHolder private constructor( private val binding1: ItemLayoutFragment1Binding?, private val binding2: ItemLayoutFragment2Binding? ) : RecyclerView.ViewHolder( binding1?.root ?: binding2?.root ?: throw IllegalArgumentException("无效的布局绑定") ) { companion object { // 根据布局ID创建对应的ViewHolder fun create(parent: ViewGroup, layoutId: Int): ViewHolder { return when(layoutId) { R.layout.item_layout_fragment1 -> { val binding = ItemLayoutFragment1Binding.inflate(LayoutInflater.from(parent.context), parent, false) ViewHolder(binding, null) } R.layout.item_layout_fragment2 -> { val binding = ItemLayoutFragment2Binding.inflate(LayoutInflater.from(parent.context), parent, false) ViewHolder(null, binding) } else -> throw IllegalArgumentException("不支持的布局ID") } } } // 绑定数据到布局 fun bind(data: MainMarkModling, listener: ContentListener) { binding1?.let { it.tvFrag1Title.text = data.title it.root.setOnClickListener { listener.onContentClick(data) } // 布局1的其他绑定逻辑 } binding2?.let { it.tvFrag2Title.text = data.title it.root.setOnClickListener { listener.onContentClick(data) } // 布局2的其他绑定逻辑 } } }
对应的,修改onCreateViewHolder和onBindViewHolder:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder.create(parent, itemLayoutId) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.bind(listOfData[position], listener) }
步骤4:在两个Fragment中初始化Adapter
最后,在两个Fragment里创建Adapter时,传入各自的布局ID即可:
Fragment1中:
val adapter = MainMarkAdapter( requireActivity() as MainActivity, fragment1DataList, contentListener, R.layout.item_layout_fragment1 ) recyclerView.adapter = adapter
Fragment2中:
val adapter = MainMarkAdapter( requireActivity() as MainActivity, fragment2DataList, contentListener, R.layout.item_layout_fragment2 ) recyclerView.adapter = adapter
这样就实现了用同一个Adapter适配不同布局的需求,后续如果要新增更多布局,只需要在ViewHolder的判断逻辑里添加对应分支即可,维护起来非常方便。
内容的提问来源于stack exchange,提问作者Nasser El Arab
相关产品推荐
相关产品推荐

