如何将TextFormField列表数据写入Firestore并实现读写更新
解决方案:从TextFormField获取列表并完成Firestore的增读改操作
1. 定义数据模型
先封装列表项数据类,方便后续序列化和操作:
class DataItem { final String id; String amount; DataItem({required this.id, required this.amount}); // 转成Firestore兼容的Map格式 Map<String, dynamic> toMap() { return { 'id': id, 'amount1': amount, }; } // 从Firestore的Map数据还原为DataItem对象 factory DataItem.fromMap(Map<String, dynamic> map) { return DataItem( id: map['id'], amount: map['amount1'], ); } }
2. 实现完整功能的页面组件
用StatefulWidget维护输入状态、本地列表数据与Firestore交互逻辑:
import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class FirestoreListPage extends StatefulWidget { const FirestoreListPage({super.key}); @override State<FirestoreListPage> createState() => _FirestoreListPageState(); } class _FirestoreListPageState extends State<FirestoreListPage> { final _firestore = FirebaseFirestore.instance; final _idController = TextEditingController(); final _amountController = TextEditingController(); List<DataItem> _items = []; // 页面初始化时自动读取Firestore数据 @override void initState() { super.initState(); _fetchData(); } // 从Firestore读取列表数据 Future<void> _fetchData() async { try { final docSnapshot = await _firestore.collection('data').doc('one').get(); if (docSnapshot.exists) { final listData = docSnapshot.data()?['list'] as List; setState(() { _items = listData.map((item) => DataItem.fromMap(item)).toList(); }); } } catch (e) { print('读取数据失败: $e'); } } // 从TextFormField获取输入,添加新项到本地列表 void _addItem() { if (_idController.text.isNotEmpty && _amountController.text.isNotEmpty) { setState(() { _items.add(DataItem( id: _idController.text, amount: _amountController.text, )); }); _idController.clear(); _amountController.clear(); } } // 修改本地列表中指定项的金额 void _updateLocalItem(int index, String newAmount) { setState(() { _items[index].amount = newAmount; }); } // 将本地列表数据写入/更新到Firestore Future<void> _saveToFirestore() async { try { final docData = { 'list': _items.map((item) => item.toMap()).toList(), }; await _firestore.collection('data').doc('one').set(docData); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('数据保存成功')), ); } catch (e) { print('写入数据失败: $e'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('保存失败: $e')), ); } } // 优化:单独更新Firestore中的单个项(避免全量更新) Future<void> _updateSingleItem(String itemId, String newAmount) async { try { final targetItem = _items.firstWhere((e) => e.id == itemId); final docRef = _firestore.collection('data').doc('one'); // 先移除旧数据,再添加更新后的数据 await docRef.update({ 'list': FieldValue.arrayRemove([targetItem.toMap()]) }); await docRef.update({ 'list': FieldValue.arrayUnion([ {'id': itemId, 'amount1': newAmount} ]) }); // 更新本地列表 setState(() { targetItem.amount = newAmount; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('项已更新')), ); } catch (e) { print('更新单个项失败: $e'); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Firestore 列表操作')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ // 输入新项的区域 Row( children: [ Expanded( child: TextFormField( controller: _idController, decoration: const InputDecoration(labelText: 'ID'), ), ), const SizedBox(width: 16), Expanded( child: TextFormField( controller: _amountController, decoration: const InputDecoration(labelText: '金额'), keyboardType: TextInputType.number, ), ), IconButton( icon: const Icon(Icons.add), onPressed: _addItem, ), ], ), const SizedBox(height: 20), // 展示列表数据的区域 Expanded( child: ListView.builder( itemCount: _items.length, itemBuilder: (context, index) { final item = _items[index]; return ListTile( title: Text(item.id), subtitle: Text('金额: ${item.amount}'), trailing: SizedBox( width: 100, child: Row( children: [ IconButton( icon: const Icon(Icons.edit), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('修改金额'), content: TextFormField( initialValue: item.amount, keyboardType: TextInputType.number, onFieldSubmitted: (value) { // 可选:用全量更新则调用_updateLocalItem,用单条更新则调用_updateSingleItem _updateSingleItem(item.id, value); Navigator.pop(context); }, ), ), ); }, ), IconButton( icon: const Icon(Icons.delete), onPressed: () { setState(() { _items.removeAt(index); }); }, ), ], ), ), ); }, ), ), // 保存按钮 ElevatedButton( onPressed: _saveToFirestore, child: const Text('保存到Firestore'), ), ], ), ), ); } @override void dispose() { _idController.dispose(); _amountController.dispose(); super.dispose(); } }
核心功能说明
- TextFormField数据获取:通过
TextEditingController绑定输入框,点击添加按钮时将输入内容转为DataItem加入本地列表。 - Firestore数据读取:页面初始化时自动拉取指定文档的列表数据,转为
DataItem后更新UI展示。 - 屏幕展示:用
ListView.builder遍历本地列表,展示每个项的ID和金额,同时提供编辑、删除操作入口。 - 更新操作:支持两种更新方式——全量更新(将整个列表重新写入Firestore)和单条更新(仅修改指定项,减少数据传输)。
内容的提问来源于stack exchange,提问作者Alpagu Burda
相关产品推荐
相关产品推荐

