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

Flutter如何根据singleLine属性每行显示1-2个列表项?

实现方案

要实现这个布局,核心是先按规则把原始卡片列表分组,再根据分组渲染对应的行布局。

1. 数据分组处理

先遍历原始列表,把符合条件的项分成单个或两个一组:

List<List<Map<String, dynamic>>> groupCards(List<Map<String, dynamic>> cards) {
  final List<List<Map<String, dynamic>>> groups = [];
  int i = 0;
  while (i < cards.length) {
    final current = cards[i];
    // 当前项是单行,单独成组
    if (current['singleLine'] == true) {
      groups.add([current]);
      i++;
    } else {
      // 检查下一项是否存在且也是非单行
      if (i + 1 < cards.length && cards[i+1]['singleLine'] == false) {
        groups.add([current, cards[i+1]]);
        i += 2;
      } else {
        // 下一项不符合,当前项单独成组
        groups.add([current]);
        i++;
      }
    }
  }
  return groups;
}

2. 布局渲染

用Column承载所有分组,每个分组根据长度渲染单行或双行布局:

Widget buildCardList() {
  final grouped = groupCards(cards);
  return Column(
    children: grouped.map((group) {
      if (group.length == 1) {
        // 单个项占满整行
        return Container(
          width: double.infinity,
          margin: const EdgeInsets.symmetric(vertical: 4),
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
            border: Border.all(color: Colors.grey),
            borderRadius: BorderRadius.circular(8),
          ),
          child: Text(group[0]['title']),
        );
      } else {
        // 两个项平分一行
        return Row(
          children: group.map((item) {
            return Expanded(
              child: Container(
                margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 2),
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Text(item['title']),
              ),
            );
          }).toList(),
        );
      }
    }).toList(),
  );
}

3. 完整使用示例

把代码整合到页面中:

class CardLayoutPage extends StatelessWidget {
  final cards = [
    {"title": "Item 1", "singleLine": true},
    {"title": "Item 2", "singleLine": false},
    {"title": "Item 3", "singleLine": false},
    {"title": "Item 4", "singleLine": true},
    {"title": "Item 5", "singleLine": true},
    {"title": "Item 6", "singleLine": false},
    {"title": "Item 7", "singleLine": true},
    {"title": "Item 8", "singleLine": false},
    {"title": "Item 9", "singleLine": false},
  ];

  CardLayoutPage({super.key});

  List<List<Map<String, dynamic>>> groupCards(List<Map<String, dynamic>> cards) {
    final List<List<Map<String, dynamic>>> groups = [];
    int i = 0;
    while (i < cards.length) {
      final current = cards[i];
      if (current['singleLine'] == true) {
        groups.add([current]);
        i++;
      } else {
        if (i + 1 < cards.length && cards[i+1]['singleLine'] == false) {
          groups.add([current, cards[i+1]]);
          i += 2;
        } else {
          groups.add([current]);
          i++;
        }
      }
    }
    return groups;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Card Layout')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: buildCardList(),
      ),
    );
  }

  Widget buildCardList() {
    final grouped = groupCards(cards);
    return Column(
      children: grouped.map((group) {
        if (group.length == 1) {
          return Container(
            width: double.infinity,
            margin: const EdgeInsets.symmetric(vertical: 4),
            padding: const EdgeInsets.all(16),
            decoration: BoxDecoration(
              border: Border.all(color: Colors.grey),
              borderRadius: BorderRadius.circular(8),
            ),
            child: Text(group[0]['title']),
          );
        } else {
          return Row(
            children: group.map((item) {
              return Expanded(
                child: Container(
                  margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 2),
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.grey),
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: Text(item['title']),
                ),
              );
            }).toList(),
          );
        }
      }).toList(),
    );
  }
}

这个方案完全符合需求:单行项占满整行,连续两个非单行项平分一行,单个非单行项也占满整行。

内容的提问来源于stack exchange,提问作者Gustavo F.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 16:38:11