如何跨类复用非静态列表,实现双页面列表同步自动更新?
嘿,这个问题其实是Flutter里很常见的「状态共享」需求——要让两个页面共用同一份数据,改一处全同步对吧?我给你几个实用的方案,从简单到进阶都有,你可以根据项目规模选~
核心思路先理清楚
你现在的问题在于列表数据是绑定在单个页面的State里的,每个页面都有自己的独立数据副本,自然没法同步。解决的关键是:
- 把列表数据抽离成全局唯一的可监听对象
- 两个页面都依赖这个对象,当数据变化时自动触发UI更新
方案1:用ValueNotifier(轻量无依赖,适合小项目)
这个方案不用额外装包,Flutter自带,适合简单的列表场景。
第一步:创建全局的可监听列表
在项目里新建一个单独的文件(比如shared_data.dart),定义一个全局的ValueNotifier:
import 'package:flutter/foundation.dart'; // 全局唯一的列表数据,初始为空 final itemListNotifier = ValueNotifier<List<String>>([]);
第二步:修改ListView页面的代码
原来的增删逻辑改成操作这个全局的itemListNotifier,并用ValueListenableBuilder监听数据变化:
import 'package:flutter/material.dart'; import 'shared_data.dart'; class ListViewPage extends StatelessWidget { const ListViewPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('ListView 页面'), actions: [ TextButton( onPressed: () => Navigator.pushNamed(context, '/stackCards'), child: const Text('去堆叠卡片页'), ), ], ), // 用ValueListenableBuilder监听数据变化,自动重建列表 body: ValueListenableBuilder<List<String>>( valueListenable: itemListNotifier, builder: (context, items, child) { return ListView.builder( itemCount: items.length, itemBuilder: (context, index) { return ListTile( title: Text(items[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () { // 修改数据时要创建新列表,不能直接修改原列表(ValueNotifier只监听引用变化) itemListNotifier.value = List.from(items)..removeAt(index); }, ), ); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { // 添加新元素,同样要创建新列表 final newItems = List.from(itemListNotifier.value); newItems.add('新元素 ${newItems.length + 1}'); itemListNotifier.value = newItems; }, child: const Icon(Icons.add), ), ); } }
第三步:修改StackCard.builder页面的代码
同样用ValueListenableBuilder监听数据,构建堆叠卡片:
import 'package:flutter/material.dart'; import 'shared_data.dart'; class StackCardPage extends StatelessWidget { const StackCardPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('堆叠卡片页面'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('返回'), ), ], ), body: ValueListenableBuilder<List<String>>( valueListenable: itemListNotifier, builder: (context, items, child) { if (items.isEmpty) { return const Center(child: Text('暂无元素')); } // 用Stack和Positioned实现堆叠效果 return Stack( children: List.generate(items.length, (index) { return Positioned( top: index * 25.0, left: index * 25.0, right: index * 25.0, child: Card( elevation: 6, color: Colors.grey[100]!.withOpacity(0.9), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( items[index], style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500), ), Align( alignment: Alignment.centerRight, child: IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () { itemListNotifier.value = List.from(items)..removeAt(index); }, ), ), ], ), ), ), ); }), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { final newItems = List.from(itemListNotifier.value); newItems.add('堆叠新元素 ${newItems.length + 1}'); itemListNotifier.value = newItems; }, child: const Icon(Icons.add), ), ); } }
方案2:用Provider(进阶推荐,适合中大型项目)
如果你的项目后续会有更多状态共享需求,Provider是Flutter生态里最常用的状态管理库之一,结构更清晰。
第一步:添加依赖
在pubspec.yaml里添加Provider:
dependencies: flutter: sdk: flutter provider: ^6.0.5 # 版本号以最新为准
然后执行flutter pub get。
第二步:创建数据模型类
新建item_list_model.dart,定义一个继承ChangeNotifier的模型,封装列表和增删方法:
import 'package:flutter/foundation.dart'; class ItemListModel extends ChangeNotifier { // 私有列表,外部只能通过getter访问 final List<String> _items = []; // 对外暴露只读的列表 List<String> get items => _items; // 添加元素,修改后通知监听者 void addItem(String item) { _items.add(item); notifyListeners(); } // 删除元素,修改后通知监听者 void removeItem(int index) { _items.removeAt(index); notifyListeners(); } }
第三步:在应用顶层注入模型
修改main.dart,用ChangeNotifierProvider把模型注入到整个应用:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'list_view_page.dart'; import 'stack_card_page.dart'; import 'item_list_model.dart'; void main() { runApp( // 全局提供ItemListModel的实例 ChangeNotifierProvider( create: (context) => ItemListModel(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '共享列表Demo', initialRoute: '/', routes: { '/': (context) => const ListViewPage(), '/stackCards': (context) => const StackCardPage(), }, ); } }
第四步:修改两个页面的代码
ListView页面:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'item_list_model.dart'; class ListViewPage extends StatelessWidget { const ListViewPage({super.key}); @override Widget build(BuildContext context) { // 获取全局的ItemListModel实例 final itemList = Provider.of<ItemListModel>(context); return Scaffold( appBar: AppBar( title: const Text('ListView 页面'), actions: [ TextButton( onPressed: () => Navigator.pushNamed(context, '/stackCards'), child: const Text('去堆叠卡片页'), ), ], ), body: ListView.builder( itemCount: itemList.items.length, itemBuilder: (context, index) { return ListTile( title: Text(itemList.items[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () => itemList.removeItem(index), ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { itemList.addItem('新元素 ${itemList.items.length + 1}'); }, child: const Icon(Icons.add), ), ); } }
StackCard页面:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'item_list_model.dart'; class StackCardPage extends StatelessWidget { const StackCardPage({super.key}); @override Widget build(BuildContext context) { final itemList = Provider.of<ItemListModel>(context); return Scaffold( appBar: AppBar( title: const Text('堆叠卡片页面'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('返回'), ), ], ), body: itemList.items.isEmpty ? const Center(child: Text('暂无元素')) : Stack( children: List.generate(itemList.items.length, (index) { return Positioned( top: index * 25.0, left: index * 25.0, right: index * 25.0, child: Card( elevation: 6, color: Colors.grey[100]!.withOpacity(0.9), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( itemList.items[index], style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500), ), Align( alignment: Alignment.centerRight, child: IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () => itemList.removeItem(index), ), ), ], ), ), ), ); }), ), floatingActionButton: FloatingActionButton( onPressed: () { itemList.addItem('堆叠新元素 ${itemList.items.length + 1}'); }, child: const Icon(Icons.add), ), ); } }
两种方案的区别
- ValueNotifier:轻量、无依赖,适合小项目或简单的状态共享场景,但全局变量的方式在大型项目里可能不易维护。
- Provider:结构清晰,适合中大型项目,支持更复杂的状态逻辑,后续扩展更方便。
不管选哪种,核心都是让两个页面依赖同一份可监听的数据,这样修改数据时,所有监听的UI都会自动同步更新~
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

