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

Dart/Flutter对比两个模型列表实现ExpansionListTile子项过滤

Flutter ExpansionList 店铺对应专属菜单实现方案

1. 核心逻辑修正

你当前的代码存在两个核心逻辑问题:

  • 原有列表的where过滤条件element.shopTitle == element.shopTitle是恒成立的判断,没有任何过滤效果
  • 两个模型没有关联规则,无法直接匹配对应菜单,有两种可行的关联方案:
    • 方案1:为CoffeeShopMenu新增relatedShopTitle字段,存储对应店铺的名称,匹配时用where过滤出relatedShopTitle等于当前店铺名称的菜单即可
    • 方案2:如果确定店铺和菜单的顺序是一一对应的(列表顺序完全对齐),可以直接通过索引对应,无需修改模型
  • 你在itemBuilder中写的双层forEach逻辑没有任何实际作用,返回值不会被使用,可以直接删除

2. 布局报错解决

你遇到的hasSize报错是因为ExpansionTile的children中嵌套的ListView.builder默认会占用无限高度,父组件没有提供明确的布局约束,只需要给内部ListView添加两个属性即可解决:

shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),

shrinkWrap让ListView根据子组件高度自适应,NeverScrollableScrollPhysics禁用内部ListView的滚动,避免和外部ListView滚动冲突。

3. 完整可运行修正代码

这里采用方案2(索引对应)实现,和你现有列表顺序匹配:

class ExpList extends StatelessWidget {
  // 去掉无用的where过滤
  List<CoffeeShop> coffeeShop = <CoffeeShop>[
    CoffeeShop(shopTitle: 'Starbucks'),
    CoffeeShop(shopTitle: 'Dunkin doghnuts'),
    CoffeeShop(shopTitle: 'Subway'),
    CoffeeShop(shopTitle: 'MCCafe'),
    CoffeeShop(shopTitle: 'Coffee Shop'),
  ];

  List<CoffeeShopMenu> coffeeMenu = <CoffeeShopMenu>[
    CoffeeShopMenu(shopMenuTitle: 'Latte and americano'),
    CoffeeShopMenu(shopMenuTitle: 'Matcha'),
    CoffeeShopMenu(shopMenuTitle: 'pie'),
    CoffeeShopMenu(shopMenuTitle: 'sandwich'),
    CoffeeShopMenu(shopMenuTitle: 'croissant'),
  ];

  // 预先把对应关系存在Map里,匹配逻辑更灵活
  late Map<String, CoffeeShopMenu> shopMenuMap = Map.fromIterables(
    coffeeShop.map((e) => e.shopTitle),
    coffeeMenu,
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: ListView.builder(
        itemCount: coffeeShop.length,
        itemBuilder: (context, index) {
          // 获取当前店铺对应的菜单
          final currentShop = coffeeShop[index];
          final currentMenu = shopMenuMap[currentShop.shopTitle];
          return ExpansionTile(
            title: Text(currentShop.shopTitle),
            subtitle: Text(currentShop.shopTitle),
            children: [
              ListView.builder(
                shrinkWrap: true,
                physics: const NeverScrollableScrollPhysics(),
                // 单个店铺对应多个菜单时,改为对应菜单列表的长度即可
                itemCount: 1,
                itemBuilder: (context, menuIndex) {
                  return ListTile(
                    title: Text(currentMenu?.shopMenuTitle ?? '暂无菜单'),
                  );
                },
              )
            ],
          );
        },
      ),
    );
  }
}

如果需要单个店铺对应多个菜单,只需要把shopMenuMap的value类型改成List<CoffeeShopMenu>,存储每个店铺对应的菜单列表即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 19:15:06