Flutter跨组件TabBarView setState刷新及SharedPreferences数据加载问题
解决Flutter Todo应用TabBarView页面刷新问题
问题核心
pendingList仅在initState阶段加载一次数据,新增任务后不会自动重新获取数据更新UIMainApp中的setState()只能刷新自身组件,无法触发TabBarView内子组件的数据重载
解决方案:通过GlobalKey触发子组件刷新
步骤1:修改pendinglist.dart,暴露刷新方法
给pendingList添加GlobalKey,并新增刷新方法让父组件可以调用:
import 'package:flutter/material.dart'; import 'package:casestudy/db_file.dart'; // 定义GlobalKey,用于父组件访问子组件状态 final GlobalKey<_pendingListState> pendingListKey = GlobalKey<_pendingListState>(); class pendingList extends StatefulWidget { const pendingList({Key? key}) : super(key: key); @override State<pendingList> createState() => _pendingListState(); } class _pendingListState extends State<pendingList>{ var db; late List data = []; @override void initState() { super.initState(); loadData(); } @override Widget build(BuildContext context) { return returnBuildContent(); } Widget returnBuildContent(){ print("pendingList Buildmethod function called"); if(data.length == 0){ return Scaffold( body: SingleChildScrollView( child: Center( child: Column( children: [ Image.asset('assets/images/noDataFound2.png'), Text("No Task are present now!",style: TextStyle(fontWeight: FontWeight.bold,color: Colors.greenAccent),) ], ), ), ), ); }else{ return Padding( padding: const EdgeInsets.all(8.0), child: ListView.builder( itemCount: data.length, itemBuilder: (BuildContext context, int index){ var dt = data[index]; return Card( child: Row( children: [ Expanded(child: Padding( padding: EdgeInsets.only(top: 10,bottom: 10,left: 15), child: Text(dt['description']), )), IconButton( onPressed: (){}, icon: Icon(Icons.edit_rounded) ), IconButton( onPressed: (){}, icon: Icon(Icons.check_circle_rounded) ), ], )); } ), ); } } loadData()async{ db = await db_file(); data = db.getData(); List highPriorityData = [], intermediatePriorityData = [], lowPriorityData = []; for(int i=0;i<data.length;i++){ if(data[i]['priority'] == "Top"){ highPriorityData.add(data[i]); }else if(data[i]['priority'] == "Intermediate"){ intermediatePriorityData.add(data[i]); }else if(data[i]['priority'] == "Low"){ lowPriorityData.add(data[i]); } } data = []; if(highPriorityData.length != 0){ data.addAll(highPriorityData); } if(intermediatePriorityData.length != 0){ data.addAll(intermediatePriorityData); } if(lowPriorityData.length != 0){ data.addAll(lowPriorityData); } setState(() {}); } // 新增:暴露给父组件的刷新方法 void refreshData() { loadData(); } }
步骤2:修改main.dart,调用子组件刷新方法
在MainApp中使用GlobalKey关联pendingList,并在保存数据后直接触发刷新:
import 'package:casestudy/db_file.dart'; import 'package:flutter/material.dart'; import 'package:casestudy/pendinglist.dart'; import 'package:casestudy/completedlist.dart'; void main() { runApp(MaterialApp(debugShowCheckedModeBanner: false,theme: ThemeData.dark(),home:MainApp())); } class MainApp extends StatefulWidget { const MainApp({super.key}); @override State<MainApp> createState() => _MainAppState(); } class _MainAppState extends State<MainApp> with TickerProviderStateMixin { TextEditingController todoDescription = TextEditingController(); late TabController _tabController; var db,data; String dropdownValue = "Top"; @override initState() { super.initState(); db = db_file(); _tabController = TabController(length: 2, vsync: this); } @override Widget build(BuildContext context) { print("build method is called"); return Scaffold( appBar: AppBar( title: const Text("Todo Application"), bottom: TabBar( tabs: [ Tab(text: "Pending"), Tab(text: "Completed"), ], controller: _tabController, indicatorColor: Colors.greenAccent, ), backgroundColor: Colors.black, ), body: TabBarView( controller: _tabController, children: <Widget>[ // 使用GlobalKey关联pendingList pendingList(key: pendingListKey), completedlist(), ], ), floatingActionButton: FloatingActionButton( onPressed: (){ showDialog( context: context, builder:(BuildContext context) { return AlertDialog( title: Text("Insert Value",style: TextStyle(color: Colors.white),), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: todoDescription, keyboardType: TextInputType.text, decoration: InputDecoration( border: OutlineInputBorder(), label: Text("Todo Task") ), ), SizedBox(height: 15,), StatefulBuilder( builder: (context,setState){ return DropdownButtonFormField( value: dropdownValue, isExpanded: true, decoration: const InputDecoration( border: OutlineInputBorder(), ), elevation: 16, onChanged: (String? value) { dropdownValue = value!; setState(() {}); }, items:[ DropdownMenuItem(child: Text("Top"),value: "Top",), DropdownMenuItem(child: Text("Intermediate"),value: "Intermediate",), DropdownMenuItem(child: Text("Low"),value: "Low",), ] ); }, ) ], ), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))), actions: [ TextButton(onPressed: (){Navigator.pop(context);}, child: const Text("Cancel",style: TextStyle(color: Colors.white),)), TextButton(onPressed: (){saveData(todoDescription.text.toString());}, child: const Text("OK",style: TextStyle(color: Colors.white),)) ], ); } ); }, backgroundColor: Colors.greenAccent, child: const Icon(Icons.add), ), ); } saveData(String todoDescription) { db.addTask(todoDescription,dropdownValue); // 保存完成后直接触发pendingList刷新 pendingListKey.currentState?.refreshData(); Navigator.pop(context); // 移除不必要的延迟等待,若addTask是异步方法,建议改为await db.addTask(...)后再刷新 } }
关键说明
- 通过
GlobalKey可以直接访问子组件的状态类方法,无需繁琐的回调传递 - 确保数据写入完成后再触发刷新,如果
addTask是异步操作,需添加await保证数据已存入SharedPreferences - 刷新逻辑直接复用
pendingList已有的loadData()方法,重新获取数据并更新UI
内容的提问来源于stack exchange,提问作者adarsh patel
相关产品推荐
相关产品推荐

