Flutter中如何将查询同值结果合并到单个Widget
问题描述
通过本地数据库sqflite执行inner join查询后,得到如下原始数据:
[ {title: First Title, subtitle: First Subtitle, content_title: A_Content Title, text: First text, color: null, warning: 0}, {title: First Title, subtitle: First Subtitle, content_title: B_Content Title, text: Second Text, color: null, warning: 0}, {title: First Title, subtitle: Second Subtitle, content_title: A_Content Title, text: Third text, color: yellow, warning: 0}, {title: First Title, subtitle: Second Subtitle, content_title: B_Content, text: Fourth text, color: null, warning: 0} ]
需要将这些数据转换为适配以下Dart模型的Widget列表:
class Category { String? subtitle; List<Content> content; Category({ required this.subtitle, required this.content }); } class Content { String? title; String? text; String? color; int? warning; // 注:原代码中`Int`应为Dart内置小写类型`int` Content({ required this.title, required this.text, required this.color, required this.warning }); }
最优实现方案
1. 数据分组与模型转换
核心思路是先按subtitle对原始数据分组,再将每组数据映射为Content对象,最后封装成Category列表。使用Dart原生Map实现分组,无需额外依赖,性能高效:
// 假设原始查询结果存储在rawData变量中 List<Map<String, dynamic>> rawData = [/* 你的sqflite查询结果 */]; // 1. 按subtitle分组 final groupedData = <String?, List<Map<String, dynamic>>>{}; for (final item in rawData) { final subtitle = item['subtitle'] as String?; groupedData.putIfAbsent(subtitle, () => []).add(item); } // 2. 转换为Category列表 final categories = groupedData.entries.map((entry) { final contents = entry.value.map((item) => Content( title: item['content_title'] as String?, text: item['text'] as String?, color: item['color'] as String?, warning: item['warning'] as int?, )).toList(); return Category(subtitle: entry.key, content: contents); }).toList();
2. 生成Widget列表
基于转换后的categories列表,使用ListView.builder构建可滚动的Widget列表,推荐用ExpansionTile展示分类与内容的层级关系:
Widget buildCategoryWidgets() { return ListView.builder( itemCount: categories.length, itemBuilder: (context, index) { final category = categories[index]; return ExpansionTile( title: Text(category.subtitle ?? '未命名分类'), children: category.content.map((content) { return ListTile( title: Text(content.title ?? ''), subtitle: Text(content.text ?? ''), tileColor: content.color != null ? _parseColor(content.color!) : null, trailing: content.warning == 1 ? const Icon(Icons.warning_amber) : null, ); }).toList(), ); }, ); } // 辅助方法:将颜色字符串转为Color对象(示例处理hex或命名颜色,根据实际需求调整) Color _parseColor(String colorStr) { if (colorStr.startsWith('#')) { return Color(int.parse(colorStr.replaceFirst('#', '0xFF'))); } // 处理命名颜色,比如"yellow" switch (colorStr.toLowerCase()) { case 'yellow': return Colors.yellow; case 'red': return Colors.red; default: return Colors.transparent; } }
关键优化点
- 分组逻辑使用
Map.putIfAbsent简化代码,比手动判断containsKey更简洁 - 模型转换采用链式
map调用,代码可读性强,符合Dart函数式编程风格 - 使用
ListView.builder实现懒加载,避免一次性创建大量Widget,提升列表滚动性能
内容的提问来源于stack exchange,提问作者Marcello
相关产品推荐
相关产品推荐

