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

Flutter分组GridView实现优化求助:高效展示多分组列表项

分组网格列表的低代码实现方案

核心思路是用单个多组件容器+多类型Item替代多个GridView,既减少冗余代码,又方便后续维护。以下是Android和Flutter两个主流平台的实现方案:

Android 端实现

1. 定义分组数据结构

data class GroupItem(
    val groupTitle: String, // 分组标题(如"汽车组")
    val items: List<String> // 分组下的子项集合
)

2. 自定义RecyclerView适配器

通过区分Item类型,同时处理分组标题和网格子项:

class GroupGridAdapter(private val dataList: List<GroupItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    companion object {
        private const val TYPE_GROUP_TITLE = 0
        private const val TYPE_GROUP_ITEM = 1
    }

    override fun getItemViewType(position: Int): Int {
        var currentPos = 0
        for (group in dataList) {
            if (currentPos == position) return TYPE_GROUP_TITLE
            currentPos++
            if (position < currentPos + group.items.size) return TYPE_GROUP_ITEM
            currentPos += group.items.size
        }
        return TYPE_GROUP_ITEM
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return if (viewType == TYPE_GROUP_TITLE) {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.item_group_title, parent, false)
            TitleViewHolder(view)
        } else {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.item_grid_child, parent, false)
            ItemViewHolder(view)
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        var currentPos = 0
        for (group in dataList) {
            if (currentPos == position) {
                (holder as TitleViewHolder).tvTitle.text = group.groupTitle
                return
            }
            currentPos++
            if (position < currentPos + group.items.size) {
                val itemIndex = position - currentPos
                (holder as ItemViewHolder).tvItem.text = group.items[itemIndex]
                return
            }
            currentPos += group.items.size
        }
    }

    override fun getItemCount(): Int {
        return dataList.sumOf { 1 + it.items.size } // 每个组=1个标题位+子项数量
    }

    class TitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvTitle: TextView = itemView.findViewById(R.id.tv_group_title)
    }

    class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvItem: TextView = itemView.findViewById(R.id.tv_grid_item)
    }
}

3. 配置布局管理器

让分组标题占满整行,子项按网格排列:

val gridLayoutManager = GridLayoutManager(context, 3) // 设置每行3个网格
gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
    override fun getSpanSize(position: Int): Int {
        return if (adapter.getItemViewType(position) == GroupGridAdapter.TYPE_GROUP_TITLE) 3 else 1
    }
}
recyclerView.layoutManager = gridLayoutManager
recyclerView.adapter = GroupGridAdapter(groupDataList)

Flutter 端实现

1. 定义分组数据类

class GroupItem {
  final String groupTitle;
  final List<String> items;

  GroupItem({required this.groupTitle, required this.items});
}

2. 简洁嵌套实现(低代码首选)

用ListView嵌套GridView,自动实现分组滚动:

ListView.builder(
  itemCount: groupDataList.length,
  itemBuilder: (context, index) {
    final group = groupDataList[index];
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 分组标题
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Text(
            group.groupTitle,
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
        ),
        // 分组子项网格
        GridView.builder(
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
            crossAxisSpacing: 8,
            mainAxisSpacing: 8,
          ),
          itemCount: group.items.length,
          itemBuilder: (context, itemIndex) {
            return Container(
              alignment: Alignment.center,
              color: Colors.grey[200],
              child: Text(group.items[itemIndex]),
            );
          },
        ),
      ],
    );
  },
)

实现效果:每个分组标题占整行,下方是对应组的网格子项,整体可纵向滚动,和你描述的示例动效完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 23:27:33