Flutter本地存储数据不显示问题:showModalBottomSheet输入数据无法在首页ListView中展示
首先咱们来拆解下你遇到的核心问题:点击保存后数据没在首页ListView显示,本质是首页没感知到数据更新,再加上几处代码逻辑的小问题,导致数据流转不通。
一、核心问题分析
1. FutureBuilder 不会自动刷新数据
你首页用的FutureBuilder依赖storage.ready这个Future,它只会在页面初始化时执行一次。当你在BottomSheet里把数据存到本地后,storage.ready已经完成了,不会再次触发FutureBuilder重新构建,所以新数据根本不会被读取并展示。
2. 保存后没触发首页状态更新
你在BottomSheet的保存按钮里调用了setState,但这个setState要么是BottomSheet内部的(因为用了StatefulBuilder),要么就算是外层页面的,也没让首页的列表重新读取最新的存储数据。
3. 数据保存逻辑的衔接漏洞
你的保存按钮里调用了_save(),但你提供的本地存储函数是_addReminder,如果_save()里没有正确把输入框的nameController.text和detailsController.text传给_addReminder,那数据根本没被添加到列表和存储里。
4. SnackBar 上下文无效
你在Navigator.pop(context)之后调用ScaffoldMessenger.of(context).showSnackBar,这里的context是BottomSheet的上下文,pop之后它已经脱离Widget树了,SnackBar大概率不会正常显示。
二、分步解决方案
1. 让首页能实时获取最新数据
方案A:用状态管理自动监听变化(推荐)
把列表数据改成用ChangeNotifier管理,这样新增数据时自动通知首页刷新:
class ReminderManager extends ChangeNotifier { List<Data> items = []; final Storage storage; int id = 0; ReminderManager(this.storage) { _loadFromStorage(); } Future<void> _loadFromStorage() async { await storage.ready; final storedItems = storage.getItem('reminder'); if (storedItems != null) { items = List<Data>.from((storedItems as List).map((item) => Data( id: item['id'], name: item['name'], details: item['details'], save: item['save'], ))); id = items.isNotEmpty ? items.last.id + 1 : 0; } notifyListeners(); } void addReminder(String name, String details) { final newItem = Data(id: id, name: name, details: details, save: true); items.add(newItem); id++; _saveToStorage(); notifyListeners(); // 通知所有监听者刷新 } Future<void> _saveToStorage() async { await storage.ready; await storage.setItem('reminder', items.map((e) => { 'id': e.id, 'name': e.name, 'details': e.details, 'save': e.save }).toList()); } }
然后在首页用Consumer包裹列表:
Consumer<ReminderManager>( builder: (context, manager, child) { return ListView.builder( itemExtent: 50.0, itemCount: manager.items.length, itemBuilder: (context, index) { final item = manager.items[index]; return remindersCard(item.name, item.details); }, ); }, )
方案B:手动触发首页刷新
打开BottomSheet时用await等待关闭,然后调用首页的setState重新读取数据:
// 打开BottomSheet的代码 await showModalBottomSheet( useRootNavigator: true, context: context, clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), builder: (context) { // 你的BottomSheet内容 }, ); // BottomSheet关闭后,手动刷新首页状态 setState(() {});
同时修改首页的FutureBuilder逻辑,每次构建都重新读取存储:
Future<List<Data>> _getLatestReminders() async { await storage.ready; final storedItems = storage.getItem('reminder'); if (storedItems == null) return []; return List<Data>.from((storedItems as List).map((item) => Data( id: item['id'], name: item['name'], details: item['details'], save: item['save'], ))); } // 首页的ListView部分 FutureBuilder<List<Data>>( future: _getLatestReminders(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } final reminders = snapshot.data ?? []; return ListView.builder( itemExtent: 50.0, itemCount: reminders.length, itemBuilder: (context, index) { return remindersCard(reminders[index].name, reminders[index].details); }, ); }, )
2. 修正BottomSheet的保存逻辑
- 确保
_save()正确传递输入框的值:
void _save() { final name = nameController.text.trim(); final details = detailsController.text.trim(); _addReminder(name, details); // 把输入值传给存储函数 }
- 修复SnackBar的上下文问题:
ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { _save(); // 先显示SnackBar再关闭BottomSheet ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Done'))); Navigator.pop(context); } }, child: Text('save'), )
3. 正确使用StatefulBuilder的状态更新
如果BottomSheet里需要更新输入验证状态,要用StatefulBuilder提供的setModalState,而不是外层页面的setState:
StatefulBuilder(builder: (context, setModalState) { return Container( padding: const EdgeInsets.all(32), child: Form( key: _formKey, child: Column( children: [ TextFormField( validator: (value) => value!.isEmpty ? 'Please enter name' : null, controller: detailsController, style: TextStyle(), border: OutlineInputBorder(borderRadius: BorderRadius.circular(5.0)), ), // 第二个TextFormField... SizedBox(height: 10), ElevatedButton( onPressed: () { setModalState(() { if (_formKey.currentState!.validate()) { _save(); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Done'))); Navigator.pop(context); } }); }, child: Text('save'), ) ], ), ), ); })
总结
最关键的就是让首页能感知到数据变化——要么用状态管理自动通知,要么手动触发刷新。同时检查数据保存的链路,确保输入框的内容确实被传到了存储函数里。
内容的提问来源于stack exchange,提问作者Abrar Lasebai

