You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter转Kotlin开发:动态多组项布局方案及嵌套RecyclerView疑问

针对动态分组训练项布局的Kotlin实现方案

先看你的场景:存在动态组数+每组内动态训练项的双层动态结构,这种情况不是必须用嵌套RecyclerView,有两种主流方案可选,按需取舍:


方案1:单RecyclerView + 多类型Item(优先推荐)

这是性能更优的方案,能避免嵌套RecyclerView带来的滑动冲突、重复测量等性能损耗。

  • 核心思路:把分组标题、单个训练项都当作RecyclerView的不同类型Item,将所有数据整合成一个统一列表后交给RecyclerView处理
  • 具体实现步骤:
    1. 定义密封类区分Item类型,比如分组标题项、训练项
    2. 把原始的分组数据结构转换为包含两种Item的扁平列表
    3. 在Adapter中重写getItemViewType,根据Item类型返回对应标识
    4. 分别实现不同类型Item的ViewHolder和数据绑定逻辑

示例代码片段:

// 定义Item类型密封类
sealed class TrainingListItem {
    data class GroupTitle(val title: String) : TrainingListItem()
    data class TrainingItem(val name: String, val setInfo: String) : TrainingListItem()
}

// RecyclerView Adapter实现
class TrainingListAdapter(private val itemList: List<TrainingListItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    companion object {
        private const val TYPE_GROUP_TITLE = 0
        private const val TYPE_TRAINING_ITEM = 1
    }

    override fun getItemViewType(position: Int): Int {
        return when (itemList[position]) {
            is TrainingListItem.GroupTitle -> TYPE_GROUP_TITLE
            is TrainingListItem.TrainingItem -> TYPE_TRAINING_ITEM
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            TYPE_GROUP_TITLE -> {
                val view = inflater.inflate(R.layout.item_group_title, parent, false)
                GroupTitleHolder(view)
            }
            else -> {
                val view = inflater.inflate(R.layout.item_training, parent, false)
                TrainingItemHolder(view)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = itemList[position]) {
            is TrainingListItem.GroupTitle -> (holder as GroupTitleHolder).bind(item.title)
            is TrainingListItem.TrainingItem -> (holder as TrainingItemHolder).bind(item.name, item.setInfo)
        }
    }

    override fun getItemCount() = itemList.size

    // ViewHolder实现
    class GroupTitleHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val titleTv: TextView = itemView.findViewById(R.id.tv_group_title)
        fun bind(title: String) {
            titleTv.text = title
        }
    }

    class TrainingItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val nameTv: TextView = itemView.findViewById(R.id.tv_training_name)
        private val setTv: TextView = itemView.findViewById(R.id.tv_set_info)
        fun bind(name: String, setInfo: String) {
            nameTv.text = name
            setTv.text = setInfo
        }
    }
}

方案2:嵌套RecyclerView(仅特殊场景使用)

只有当每组训练项需要独立滑动逻辑,或业务上必须将每组作为独立可复用组件时,才考虑嵌套:

  • 关键优化点:
    1. 给内层RecyclerView设置nestedScrollingEnabled = false,避免滑动冲突
    2. 给内层RecyclerView的布局管理器设置固定高度,减少重复测量
    3. 尽量简化内层布局,避免过度绘制

总结:绝大多数场景下优先选择单RecyclerView+多类型Item,性能更好,代码维护成本更低。

内容的提问来源于stack exchange,提问作者Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:06:22