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

Flutter中如何将ListView.separated表格导出为CSV文件

完善Flutter ListView表格数据导出CSV功能

1. 确认依赖配置

先确保pubspec.yaml里包含以下依赖(如果没加path_provider需要补上,用来获取存储路径):

dependencies:
  flutter:
    sdk: flutter
  csv: ^5.0.2
  permission_handler: ^10.2.0
  path_provider: ^2.0.11

执行flutter pub get更新依赖。

2. 完整实现代码

下面是整合了导出功能的完整代码,包含权限请求、CSV转换、文件写入逻辑:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:csv/csv.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path_provider/path_provider.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CSV导出示例',
      home: const TablePage(),
    );
  }
}

class TablePage extends StatefulWidget {
  const TablePage({super.key});

  @override
  State<TablePage> createState() => _TablePageState();
}

class _TablePageState extends State<TablePage> {
  // 模拟ListView表格的数据,替换成你自己的实际数据
  final List<Map<String, dynamic>> _tableData = [
    {'ID': '1', '姓名': '张三', '年龄': '25', '职位': '开发工程师'},
    {'ID': '2', '姓名': '李四', '年龄': '30', '职位': '产品经理'},
    {'ID': '3', '姓名': '王五', '年龄': '28', '职位': 'UI设计师'},
  ];

  // 导出CSV核心方法
  Future<void> _exportToCsv() async {
    // 1. 请求存储权限
    var status = await Permission.storage.request();
    if (!status.isGranted) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('需要存储权限才能导出文件')),
      );
      return;
    }

    try {
      // 2. 转换数据为CSV格式
      // 先准备表头
      final List<String> headers = _tableData.first.keys.toList();
      // 准备数据行
      final List<List<dynamic>> rows = [
        headers,
        ..._tableData.map((item) => headers.map((header) => item[header]).toList()),
      ];
      // 转换为CSV字符串
      final csvString = const ListToCsvConverter().convert(rows);

      // 3. 获取存储路径并写入文件
      final Directory? externalDir = await getExternalStorageDirectory();
      if (externalDir == null) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('无法获取存储路径')),
        );
        return;
      }
      // 创建文件路径
      final File file = File('${externalDir.path}/表格数据_${DateTime.now().millisecondsSinceEpoch}.csv');
      // 写入CSV内容
      await file.writeAsString(csvString);

      // 提示导出成功
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('文件已导出至:${file.path}')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('导出失败:$e')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('表格数据'),
        actions: [
          // 导出按钮
          IconButton(
            icon: const Icon(Icons.download),
            onPressed: _exportToCsv,
            tooltip: '导出CSV',
          ),
        ],
      ),
      body: ListView.separated(
        padding: const EdgeInsets.all(16),
        itemCount: _tableData.length,
        separatorBuilder: (context, index) => const Divider(height: 1),
        itemBuilder: (context, index) {
          final item = _tableData[index];
          return Row(
            children: [
              Expanded(flex: 1, child: Text(item['ID']!)),
              Expanded(flex: 2, child: Text(item['姓名']!)),
              Expanded(flex: 1, child: Text(item['年龄']!)),
              Expanded(flex: 2, child: Text(item['职位']!)),
            ],
          );
        },
      ),
    );
  }
}

关键说明

  • 权限处理:针对Android和iOS的存储权限做了请求,确保有权限才能写入文件
  • CSV转换:先提取表头,再把每行数据对应到表头列,确保CSV格式正确
  • 文件命名:用时间戳避免文件名重复,防止覆盖旧文件
  • 错误处理:捕获异常并提示用户,避免崩溃

你只需要把_tableData替换成你自己的实际数据列表即可,导出按钮点击后会把数据保存到设备的外部存储目录下。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:12:34