Flutter中按下按钮弹窗时,如何禁用Column组件内所有按钮?
实现Flutter动态按钮组的全局禁用(按下按钮到弹窗关闭期间)
你当前的代码中每个按钮单独维护isButtonEnabled状态,只能禁用当前点击的按钮,无法实现全局禁用所有按钮的需求。要解决这个问题,需要把全局禁用状态提升到父组件的State中,统一控制所有按钮的可点击性,并且等待弹窗关闭后再恢复按钮状态。
具体实现步骤:
- 在父组件的
State类中添加全局状态变量:
bool isGlobalProcessing = false;
移除每个按钮内部的
isButtonEnabled变量,所有按钮的onPressed判断都依赖这个全局状态。在按钮点击逻辑中,先设置全局状态为禁用,执行API请求和打印操作后,使用await等待弹窗关闭(
showDialog返回Future,弹窗关闭时Future才会完成),最后恢复全局状态。
修改后的完整代码片段:
// 注意:isGlobalProcessing需要定义在当前页面的State类中 bool isGlobalProcessing = false; int isLoadingIndex = -1; // ... 其他代码 ... FutureBuilder<Map<String, dynamic>>( future: _apiService.fetchData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError || !snapshot.hasData) { return Center(child: Text('Error: ${snapshot.error ?? "No data"}')); } final String companyName = snapshot.data!['company']?.name ?? ''; final List<dynamic> categoriesData = snapshot.data!['categories'] ?? []; return Column( children: categoriesData.map<Widget>((category) { final String nameEn = category.nameEn; final String nameBn = category.nameBn; bool isProcessing = false; return StatefulBuilder( builder: (context, setState) { final bool isSelected = isLoadingIndex == categoriesData.indexOf(category); return Column( children: [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primary, fixedSize: Size(screenWidth * 0.8, screenHeight * 0.1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ), ), onPressed: isGlobalProcessing ? null : () async { // 设置全局禁用状态 setState(() { isGlobalProcessing = true; isLoadingIndex = categoriesData.indexOf(category); isProcessing = true; }); final int categoryID = category.id; final url = URL; final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { final responseData = json.decode(response.body); print(responseData); final data = responseData['data']; final Token = data['token']; final Time = data['time']; print('Token: $Token, Time and Date: $Time'); final SunmiPosSdk sunmiPosSdk = SunmiPosSdk(); await sunmiPosSdk.printReceipt(context, '$Token', '$Time', '$nameEn', '$nameBn', '$companyName'); // await弹窗,等待弹窗关闭 await showDialog( context: context, barrierColor: Colors.grey.withOpacity(0.5), barrierDismissible: false, builder: (BuildContext context) { return Center( child: buildAlertDialog(Token, Time, '$nameEn ($nameBn)'), ); }, ); } else { print('Failed to fetch data: ${response.statusCode}'); } // 弹窗关闭后恢复全局状态 setState(() { isGlobalProcessing = false; isLoadingIndex = -1; isProcessing = false; }); }, child: FittedBox( fit: BoxFit.scaleDown, child: Text( '$nameEn ($nameBn)', style: const TextStyle( fontSize: 25, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), if (isProcessing) GestureDetector( onTap: () {}, child: Container( color: Colors.transparent, ), ), SizedBox(height: screenHeight * 0.01), ], ); }, ); }).toList(), ); }, ),
关键说明:
- 全局状态控制:
isGlobalProcessing是父State中的变量,所有按钮的onPressed都依赖它,确保任何一个按钮点击后,所有按钮都会被禁用。 - 等待弹窗关闭:使用
await showDialog(),确保只有当用户关闭弹窗后,才会执行恢复按钮状态的代码,完全覆盖“按钮按下到弹窗关闭”的时间段。 - 局部状态保留:
isProcessing和isLoadingIndex可以保留,用于显示当前按钮的加载状态(比如加载动画)。
内容的提问来源于stack exchange,提问作者Hans_
相关产品推荐
相关产品推荐

