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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:07:50