从子视图返回后如何更新Flutter AppBar中的值?
问题分析与解决方案
核心问题
你遇到的问题本质有两点:
- 局部变量被重置:
amount是build方法内的局部变量,每次组件重建(包括setState触发的重建)都会重新从widget.jobObject.totalAmount赋值,你在setState里修改的只是临时变量,下次build就会被覆盖。 - 传入的Job对象未更新:
widget.jobObject是页面初始化时传入的旧数据,添加交易后后端的Job总额已更新,但前端这个对象没有同步刷新,始终保留初始值。
解决方案(两种可选)
方案一:通过交易列表计算总额(推荐)
既然你已经在监听该作业的交易列表,直接从交易数据中累加计算总额即可,无需依赖传入的Job对象。这样交易列表更新时,总额会自动同步:
class _TxnsByJobState extends ConsumerState<TxnsByJob> { @override Widget build(BuildContext context) { final jobTxnsListValue = ref.watch(transactionsListForJobProvider(widget.jobObject.id!)); // 计算总额:有交易数据则累加,无数据时用初始值兜底 num amount = widget.jobObject.totalAmount; if (jobTxnsListValue.hasValue && jobTxnsListValue.value != null) { amount = jobTxnsListValue.value!.fold( 0, (sum, txn) => sum + txn.amount, ); } return Scaffold( appBar: AppBar( title: StyledHeadline(widget.jobObject.name), bottom: PreferredSize( preferredSize: const Size.fromHeight(12.0), child: StyledNumberText( FbFormatter.formatCurrency(amount.toDouble()), amount >= 0 ? AppColors.greenColor : AppColors.redColor, ), ), ), body: jobTxnsListValue.when( data: (txns) => ListView.builder( itemCount: txns.length, itemBuilder: (context, index) { return FbTile( title: txns[index].payee.name, subtitle: txns[index].date, amount: txns[index].amount as double, note: txns[index].costcode.name, category: txns[index].costcode.category); }, ), error: (e, st) => Center(child: Text('Error! $e')), loading: () => const Center(child: CircularProgressIndicator.adaptive()), ), floatingActionButton: FloatingActionButton( onPressed: () async { await Navigator.of(context).push( MaterialPageRoute( fullscreenDialog: true, builder: (context) => AddTransactionTest(job: widget.jobObject), ), ); // 仅需失效交易列表provider,总额会随交易数据自动计算更新 ref.invalidate(transactionsListForJobProvider(widget.jobObject.id!)); }, child: const Icon(Icons.add, size: 36), ), ); } }
方案二:为Job对象单独创建Provider
如果需要严格同步后端的Job对象数据,可以为单个Job创建Provider,更新交易后重新拉取最新的Job数据:
- 先定义Job的Provider:
final jobProvider = FutureProvider.family<FbJob, String>((ref, jobId) async { // 从Supabase拉取最新的Job对象 final response = await supabase.from('jobs').select().eq('id', jobId).single(); return FbJob.fromJson(response); });
- 修改页面代码:
class _TxnsByJobState extends ConsumerState<TxnsByJob> { @override Widget build(BuildContext context) { final jobValue = ref.watch(jobProvider(widget.jobObject.id!)); return jobValue.when( data: (job) { final jobTxnsListValue = ref.watch(transactionsListForJobProvider(job.id!)); return Scaffold( appBar: AppBar( title: StyledHeadline(job.name), bottom: PreferredSize( preferredSize: const Size.fromHeight(12.0), child: StyledNumberText( FbFormatter.formatCurrency(job.totalAmount.toDouble()), job.totalAmount >= 0 ? AppColors.greenColor : AppColors.redColor, ), ), ), body: jobTxnsListValue.when( data: (txns) => ListView.builder( itemCount: txns.length, itemBuilder: (context, index) { return FbTile( title: txns[index].payee.name, subtitle: txns[index].date, amount: txns[index].amount as double, note: txns[index].costcode.name, category: txns[index].costcode.category); }, ), error: (e, st) => Center(child: Text('Error! $e')), loading: () => const Center(child: CircularProgressIndicator.adaptive()), ), floatingActionButton: FloatingActionButton( onPressed: () async { await Navigator.of(context).push( MaterialPageRoute( fullscreenDialog: true, builder: (context) => AddTransactionTest(job: job), ), ); // 同时失效Job和交易列表的Provider,拉取最新数据 ref.invalidate(jobProvider(job.id!)); ref.invalidate(transactionsListForJobProvider(job.id!)); }, child: const Icon(Icons.add, size: 36), ), ); }, error: (e, st) => Center(child: Text('Error! $e')), loading: () => const Center(child: CircularProgressIndicator.adaptive()), ); } }
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

