Flutter Provider实现自定义按钮加载时显示CircularProgressIndicator
问题分析与解决方案
问题根源
你的TrustyButton组件内部通过ChangeNotifierProvider(create: (context) => OrderService())创建了一个独立的OrderService实例,而调用deleteOrderWithId方法时使用的是上层(如订单列表页面)提供的另一个OrderService实例。两个实例完全独立,删除订单时修改的是上层实例的isLoading,按钮监听的自身实例状态从未改变,因此UI没有更新。
解决方案
1. 移除按钮内部的Provider,复用上层实例
修改TrustyButton,让它直接从父级context获取已有的OrderService实例,不再自行创建:
import ... class TrustyButton extends StatelessWidget { final void Function() onTap; final String text; final ButtonType type; final Icon? icon; TrustyButton({ super.key, required this.onTap, required this.text, required this.type, this.icon, }); final Map<ButtonType, Map<String, Color>> color = {...} @override Widget build(BuildContext context) { return Consumer<OrderService>( builder: (context, orderService, _) => GestureDetector( onTap: onTap, child: Opacity( opacity: orderService.isLoading ? 0.5 : 1, child: Container( height: 56, decoration: BoxDecoration( color: color[type]!['backgroundColor']!, borderRadius: const BorderRadius.all( Radius.circular(20), ), boxShadow: [ BoxShadow( color: const Color(0x15000000), blurRadius: 10, spreadRadius: 0, offset: Offset.fromDirection(2, 2), ), ], ), child: Center( child: orderService.isLoading ? const CircularProgressIndicator( color: Colors.white, ) : renderButtonContent(), ), ), ), ), ); } }
2. 确保上层已提供OrderService实例
在使用TrustyButton的页面(如订单列表页)上层,必须通过ChangeNotifierProvider提供全局/页面级的OrderService实例,示例:
class OrderListPage extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => OrderService(), child: Scaffold( body: // 订单列表内容 // 使用按钮的位置 TrustyButton( onTap: () { // 调用上层实例的删除方法,listen: false避免不必要的监听 Provider.of<OrderService>(context, listen: false) .deleteOrderWithId(订单ID, context); }, text: "删除订单", type: ButtonType.danger, ), ), ); } }
额外注意
- 调用
deleteOrderWithId时需添加listen: false,因为此处仅需执行方法,不需要监听状态变化 - 如果你的
OrderService是全局提供的(如在MaterialApp上层),页面层无需重复创建Provider,直接使用即可
内容的提问来源于stack exchange,提问作者Felix Hohn
相关产品推荐
相关产品推荐

