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.
相关产品推荐
相关产品推荐

