ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Flutter对话框与提示组件开发指南

Flutter对话框与提示组件开发指南 1. Flutter对话框与提示组件概述在移动应用开发中对话框(Dialog)和提示(Toast/Snackbar)是最常用的用户交互组件之一。Flutter提供了丰富灵活的对话框和提示组件体系可以满足各种场景下的用户反馈需求。作为跨平台开发框架Flutter的对话框组件具有以下特点完全自定义的UI设计能力统一的API接口适配iOS和Android平台丰富的内置动画效果灵活的定位和显示控制1.1 核心组件分类Flutter中的对话框和提示相关组件主要分为以下几类AlertDialog- 标准警告对话框包含标题、内容和操作按钮SimpleDialog- 简单选择对话框提供多个选项供用户选择BottomSheet- 底部弹出面板适合展示更多内容SnackBar- 轻量级底部提示自动消失Toast- 通过第三方库实现的短暂提示Custom Dialog- 完全自定义的对话框组件2. AlertDialog详解与实战2.1 基础AlertDialog使用AlertDialog是最常用的对话框类型适合需要用户确认或做出选择的场景。showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(提示), content: Text(确定要删除这条记录吗), actions: Widget[ TextButton( child: Text(取消), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( child: Text(确定), onPressed: () { // 执行删除操作 Navigator.of(context).pop(); }, ), ], ); }, );2.2 高级配置选项AlertDialog提供了丰富的配置选项AlertDialog( title: Text(高级设置), titlePadding: EdgeInsets.all(20), titleTextStyle: TextStyle(color: Colors.red, fontSize: 20), content: Text(请选择您的偏好设置), contentPadding: EdgeInsets.symmetric(horizontal: 15), contentTextStyle: TextStyle(color: Colors.grey), backgroundColor: Colors.white, elevation: 10, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), actions: [...], )2.3 实际应用技巧对话框堆叠管理使用Navigator的pop和push方法管理多个对话框的显示顺序异步操作处理在对话框按钮点击时执行异步操作并显示加载状态onPressed: () async { setState(() _isLoading true); await _performDelete(); setState(() _isLoading false); Navigator.of(context).pop(); }动态内容更新使用StatefulBuilder实现对话框内容的动态更新content: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return Column( children: [ CheckboxListTile( value: _isChecked, onChanged: (bool? value) { setState(() _isChecked value!); }, title: Text(同意条款), ), ], ); }, ),3. SimpleDialog与选择型对话框3.1 SimpleDialog基础用法SimpleDialog适合提供多个选项供用户选择showDialog( context: context, builder: (BuildContext context) { return SimpleDialog( title: Text(选择颜色), children: Widget[ SimpleDialogOption( onPressed: () { Navigator.pop(context, Colors.red); }, child: Text(红色), ), SimpleDialogOption( onPressed: () { Navigator.pop(context, Colors.green); }, child: Text(绿色), ), SimpleDialogOption( onPressed: () { Navigator.pop(context, Colors.blue); }, child: Text(蓝色), ), ], ); }, ).then((value) { if (value ! null) { setState(() _selectedColor value); } });3.2 自定义选择对话框对于更复杂的选择需求可以完全自定义对话框内容showDialog( context: context, builder: (context) Dialog( child: Container( padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(自定义选择, style: Theme.of(context).textTheme.headline6), Divider(), ListView.builder( shrinkWrap: true, itemCount: _options.length, itemBuilder: (ctx, index) ListTile( title: Text(_options[index]), onTap: () Navigator.pop(context, _options[index]), ), ), ], ), ), ), );4. BottomSheet设计与实现4.1 模态BottomSheet模态BottomSheet会阻止用户与其他界面元素交互showModalBottomSheet( context: context, builder: (context) Container( padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(操作菜单, style: TextStyle(fontSize: 18)), SizedBox(height: 20), ListTile( leading: Icon(Icons.share), title: Text(分享), onTap: () { Navigator.pop(context); _shareContent(); }, ), ListTile( leading: Icon(Icons.delete), title: Text(删除), onTap: () { Navigator.pop(context); _deleteItem(); }, ), ], ), ), );4.2 非模态BottomSheet非模态BottomSheet允许用户同时与界面其他部分交互final bottomSheetController showBottomSheet( context: context, builder: (context) Container(...), ); // 可以通过controller手动关闭 bottomSheetController.close();4.3 高级技巧可拖动BottomSheetshowModalBottomSheet( context: context, isScrollControlled: true, // 允许全屏显示 builder: (context) DraggableScrollableSheet( expand: false, initialChildSize: 0.5, // 初始高度为屏幕50% minChildSize: 0.3, // 最小高度30% maxChildSize: 0.9, // 最大高度90% builder: (context, scrollController) { return ListView.builder( controller: scrollController, itemCount: 30, itemBuilder: (ctx, index) ListTile( title: Text(项目 $index), ), ); }, ), );5. SnackBar与Toast提示5.1 SnackBar基础使用SnackBar是Material Design推荐的轻量级提示方式final snackBar SnackBar( content: Text(操作已成功完成!), duration: Duration(seconds: 2), action: SnackBarAction( label: 撤销, onPressed: () { // 执行撤销操作 }, ), ); ScaffoldMessenger.of(context).showSnackBar(snackBar);5.2 自定义SnackBarSnackBar( content: Row( children: [ Icon(Icons.check_circle, color: Colors.white), SizedBox(width: 10), Expanded(child: Text(文件上传成功)), ], ), backgroundColor: Colors.green, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), margin: EdgeInsets.all(20), );5.3 Toast实现方案Flutter本身没有内置Toast组件可以通过以下方式实现使用fluttertoast插件Fluttertoast.showToast( msg: 这是一条Toast消息, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0 );自定义Toast组件void showCustomToast(BuildContext context, String message) { final overlay Overlay.of(context); final overlayEntry OverlayEntry( builder: (context) Positioned( top: MediaQuery.of(context).size.height * 0.8, width: MediaQuery.of(context).size.width, child: Center( child: Material( color: Colors.transparent, child: Container( padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), decoration: BoxDecoration( color: Colors.black87, borderRadius: BorderRadius.circular(20), ), child: Text(message, style: TextStyle(color: Colors.white)), ), ), ), ), ); overlay.insert(overlayEntry); Future.delayed(Duration(seconds: 2)).then((_) overlayEntry.remove()); }6. 自定义对话框开发6.1 完全自定义对话框showDialog( context: context, builder: (context) Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: Stack( clipBehavior: Clip.none, alignment: Alignment.topCenter, children: [ Container( padding: EdgeInsets.all(20), height: 300, child: Column( children: [ SizedBox(height: 30), Text(自定义标题, style: TextStyle(fontWeight: FontWeight.bold)), SizedBox(height: 20), Expanded( child: ListView( children: [ Text(这里是自定义内容区域...), ], ), ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( child: Text(关闭), onPressed: () Navigator.pop(context), ), ], ), ], ), ), Positioned( top: -50, child: CircleAvatar( radius: 50, backgroundColor: Colors.blue, child: Icon(Icons.check, size: 50, color: Colors.white), ), ), ], ), ), );6.2 对话框动画效果showGeneralDialog( context: context, pageBuilder: (context, animation, secondaryAnimation) { return ScaleTransition( scale: CurvedAnimation( parent: animation, curve: Curves.easeOutBack, ), child: AlertDialog( title: Text(带动画的对话框), content: Text(这个对话框有缩放动画效果), actions: [...], ), ); }, transitionDuration: Duration(milliseconds: 400), );6.3 全屏自定义对话框showDialog( context: context, barrierDismissible: false, builder: (context) Dialog( insetPadding: EdgeInsets.zero, child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: Stack( children: [ // 对话框内容 Positioned( right: 20, top: 20, child: IconButton( icon: Icon(Icons.close), onPressed: () Navigator.pop(context), ), ), ], ), ), ), );7. 对话框状态管理与最佳实践7.1 状态管理方案使用Provider管理对话框状态class DialogProvider with ChangeNotifier { bool _isLoading false; bool get isLoading _isLoading; void showLoading() { _isLoading true; notifyListeners(); } void hideLoading() { _isLoading false; notifyListeners(); } } // 在UI中使用 ConsumerDialogProvider( builder: (context, provider, child) { if (provider.isLoading) { return AlertDialog( content: Row( children: [ CircularProgressIndicator(), SizedBox(width: 20), Text(加载中...), ], ), ); } return SizedBox(); }, )使用BLoC模式class DialogBloc { final _dialogController StreamControllerWidget?(); StreamWidget? get dialogStream _dialogController.stream; void showDialog(Widget dialog) { _dialogController.add(dialog); } void hideDialog() { _dialogController.add(null); } void dispose() { _dialogController.close(); } } // 在UI层监听 StreamBuilderWidget?( stream: dialogBloc.dialogStream, builder: (context, snapshot) { if (snapshot.hasData snapshot.data ! null) { return Stack( children: [ // 主界面内容 Positioned.fill(child: snapshot.data!), ], ); } return Container(); }, )7.2 性能优化技巧避免不必要的重建将对话框内容提取到单独的Widget中使用const构造函数延迟加载内容对于复杂对话框使用FutureBuilder延迟加载内容复用对话框实例对于频繁显示的对话框考虑缓存实例7.3 测试策略Widget测试验证对话框是否按预期显示testWidgets(测试AlertDialog显示, (tester) async { await tester.pumpWidget(MaterialApp(home: MyApp())); await tester.tap(find.byType(ElevatedButton)); await tester.pump(); expect(find.text(提示标题), findsOneWidget); expect(find.text(确定), findsOneWidget); });集成测试验证对话框交互流程testWidgets(测试对话框交互, (tester) async { await tester.pumpWidget(MaterialApp(home: MyApp())); await tester.tap(find.byType(ElevatedButton)); await tester.pumpAndSettle(); await tester.tap(find.text(确定)); await tester.pump(); expect(find.text(操作成功), findsOneWidget); });8. 常见问题与解决方案8.1 对话框显示问题排查对话框不显示确保在MaterialApp或CupertinoApp的上下文中调用检查BuildContext是否正确确认没有其他对话框正在显示对话框位置不正确检查父容器的约束条件对于自定义位置对话框确保计算正确的偏移量对话框背景透明问题设置barrierColor: Colors.black54调整蒙层颜色确保对话框本身有背景色8.2 性能问题优化对话框显示卡顿减少对话框内容的复杂度预加载可能需要的资源使用RepaintBoundary隔离重绘区域内存泄漏问题确保对话框关闭时释放所有资源避免在对话框中使用全局静态变量8.3 跨平台适配问题iOS和Android样式差异使用Theme和Platform类适配不同平台考虑使用CupertinoAlertDialog专门适配iOS风格Platform.isIOS ? CupertinoAlertDialog(...) : AlertDialog(...)Web平台特殊问题处理浏览器返回按钮与对话框的关系适配不同屏幕尺寸下的对话框显示国际化支持使用Localizations处理文本翻译考虑RTL(从右到左)语言的布局适配Text( S.of(context).dialogTitle, textDirection: Directionality.of(context), )9. 高级应用场景9.1 登录对话框实现showDialog( context: context, builder: (context) Dialog( child: Container( padding: EdgeInsets.all(20), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(用户登录, style: Theme.of(context).textTheme.headline6), SizedBox(height: 20), TextFormField( decoration: InputDecoration(labelText: 用户名), validator: (value) value!.isEmpty ? 请输入用户名 : null, ), TextFormField( decoration: InputDecoration(labelText: 密码), obscureText: true, validator: (value) value!.isEmpty ? 请输入密码 : null, ), SizedBox(height: 20), ElevatedButton( child: Text(登录), onPressed: () { if (_formKey.currentState!.validate()) { _performLogin(); Navigator.pop(context); } }, ), ], ), ), ), ), );9.2 权限请求对话框Futurebool showPermissionDialog(BuildContext context) async { return await showDialogbool( context: context, barrierDismissible: false, builder: (context) AlertDialog( title: Text(需要位置权限), content: Text(应用需要访问您的位置信息以提供附近服务), actions: [ TextButton( child: Text(拒绝), onPressed: () Navigator.pop(context, false), ), TextButton( child: Text(允许), onPressed: () Navigator.pop(context, true), ), ], ), ) ?? false; }9.3 评分对话框void showRatingDialog(BuildContext context) { double _rating 3; showDialog( context: context, builder: (context) StatefulBuilder( builder: (context, setState) { return AlertDialog( title: Text(为应用评分), content: Column( mainAxisSize: MainAxisSize.min, children: [ Text(您喜欢这个应用吗), SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(5, (index) { return IconButton( icon: Icon( index _rating ? Icons.star : Icons.star_border, color: Colors.amber, size: 30, ), onPressed: () setState(() _rating index 1.0), ); }), ), ], ), actions: [ TextButton( child: Text(取消), onPressed: () Navigator.pop(context), ), TextButton( child: Text(提交), onPressed: () { _submitRating(_rating); Navigator.pop(context); }, ), ], ); }, ), ); }10. 对话框主题与样式统一10.1 全局对话框样式配置在MaterialApp中统一配置对话框主题MaterialApp( theme: ThemeData( dialogTheme: DialogTheme( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), elevation: 10, backgroundColor: Colors.white, titleTextStyle: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black, ), contentTextStyle: TextStyle( fontSize: 16, color: Colors.grey[800], ), ), ), )10.2 自定义对话框主题创建继承自Theme的自定义对话框样式showDialog( context: context, builder: (context) Theme( data: Theme.of(context).copyWith( dialogBackgroundColor: Colors.blueGrey[900], textTheme: TextTheme( headline6: TextStyle(color: Colors.white), bodyText2: TextStyle(color: Colors.white70), ), buttonTheme: ButtonThemeData( textTheme: ButtonTextTheme.primary, ), ), child: AlertDialog( title: Text(夜间模式对话框), content: Text(这是自定义主题的对话框), actions: [...], ), ), );10.3 响应式对话框设计根据屏幕尺寸调整对话框大小和布局showDialog( context: context, builder: (context) LayoutBuilder( builder: (context, constraints) { final isSmallScreen constraints.maxWidth 600; return Dialog( child: Container( width: isSmallScreen ? constraints.maxWidth * 0.9 : constraints.maxWidth * 0.6, padding: EdgeInsets.all(isSmallScreen ? 16 : 24), child: ... ), ); }, ), );11. 对话框与路由深度集成11.1 对话框作为独立路由将对话框注册为应用路由MaterialApp( routes: { /confirmDialog: (context) Builder( builder: (context) AlertDialog( title: Text(确认操作), content: Text(您确定要执行此操作吗), actions: [...], ), ), }, ) // 通过路由名显示对话框 Navigator.pushNamed(context, /confirmDialog);11.2 对话框结果处理使用Future处理对话框返回结果final result await showDialogbool( context: context, builder: (context) AlertDialog(...), ); if (result true) { // 用户点击了确定 } else { // 用户取消或关闭对话框 }11.3 对话框与页面转场动画自定义对话框显示/隐藏动画Navigator.push( context, PageRouteBuilder( opaque: false, pageBuilder: (context, animation, secondaryAnimation) { return FadeTransition( opacity: animation, child: ScaleTransition( scale: animation, child: AlertDialog(...), ), ); }, ), );12. 测试与调试技巧12.1 对话框调试工具Flutter Inspector检查对话框的Widget树和布局Debug Paint显示对话框边界和填充void main() { debugPaintSizeEnabled true; runApp(MyApp()); }12.2 常见错误排查No MaterialLocalizations found错误确保在MaterialApp或CupertinoApp中使用对话框检查是否正确传递了BuildContextsetState() called after dispose()错误在对话框关闭前取消所有异步操作使用mounted属性检查Widget是否仍然挂载if (mounted) setState(() {...});12.3 性能分析使用Flutter性能工具分析对话框渲染性能性能OverlayMaterialApp( showPerformanceOverlay: true, )Dart DevTools分析对话框的渲染时间和GPU使用情况13. 第三方对话框库推荐13.1 awesome_dialog提供多种预定义样式的精美对话框AwesomeDialog( context: context, dialogType: DialogType.SUCCES, animType: AnimType.BOTTOM_SLIDE, title: 操作成功, desc: 您的数据已成功保存, btnOkOnPress: () {}, ).show();13.2 flutter_animated_dialog支持丰富动画效果的对话框showAnimatedDialog( context: context, barrierDismissible: true, builder: (context) AlertDialog(...), animationType: DialogTransitionType.slideFromBottom, curve: Curves.fastOutSlowIn, duration: Duration(milliseconds: 500), );13.3 rflutter_alert高度可定制的多功能对话框Alert( context: context, type: AlertType.warning, title: 警告, desc: 确定要删除吗此操作不可撤销, buttons: [ DialogButton( child: Text(取消), onPressed: () Navigator.pop(context), ), DialogButton( child: Text(确定), onPressed: () { _deleteItem(); Navigator.pop(context); }, ), ], ).show();14. 无障碍访问支持14.1 对话框无障碍属性确保对话框对辅助技术友好AlertDialog( semanticLabel: 操作确认对话框, content: Text( 确定要删除此项目吗, semanticsLabel: 确认删除操作的提示文本, ), actions: [ TextButton( child: Text(取消), onPressed: () Navigator.pop(context), semanticLabel: 取消删除按钮, ), TextButton( child: Text(确定), onPressed: () Navigator.pop(context), semanticLabel: 确认删除按钮, ), ], )14.2 焦点管理正确处理对话框内的焦点顺序FocusScope.of(context).requestFocus(_firstFocusNode); AlertDialog( content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( focusNode: _firstFocusNode, decoration: InputDecoration(labelText: 用户名), ), TextField( focusNode: _secondFocusNode, decoration: InputDecoration(labelText: 密码), ), ], ), )14.3 屏幕阅读器支持优化对话框的屏幕阅读器体验Semantics( label: 对话框标题, child: Text(重要提示, style: TextStyle(fontSize: 20)), ), Semantics( label: 对话框内容, child: Text(请确认您的操作选择, style: TextStyle(fontSize: 16)), ),15. 对话框国际化与本地化15.1 多语言支持使用flutter_localizations实现多语言对话框MaterialApp( localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: [ Locale(en, US), Locale(zh, CN), ], )15.2 动态文本加载根据当前语言环境加载不同文本AlertDialog( title: Text(AppLocalizations.of(context)!.dialogTitle), content: Text(AppLocalizations.of(context)!.dialogContent), actions: [ TextButton( child: Text(AppLocalizations.of(context)!.cancel), onPressed: () Navigator.pop(context), ), TextButton( child: Text(AppLocalizations.of(context)!.confirm), onPressed: () Navigator.pop(context), ), ], )15.3 RTL布局支持适配从右到左的语言Directionality( textDirection: TextDirection.rtl, child: AlertDialog( title: Text(RTL对话框), content: Text(这是支持从右到左布局的对话框), actions: [ TextButton( child: Text(取消), onPressed: () Navigator.pop(context), ), TextButton( child: Text(确定), onPressed: () Navigator.pop(context), ), ], ), )16. 对话框与状态管理框架集成16.1 与Riverpod集成使用Riverpod管理对话框状态final dialogProvider StateProviderWidget?((ref) null); // 显示对话框 ref.read(dialogProvider.notifier).state AlertDialog(...); // 隐藏对话框 ref.read(dialogProvider.notifier).state null; // 在UI中监听 Consumer( builder: (context, ref, child) { final dialog ref.watch(dialogProvider); return Stack( children: [ // 主界面内容 if (dialog ! null) dialog, ], ); }, )16.2 与GetX集成使用GetX显示对话框Get.dialog( AlertDialog( title: Text(GetX对话框), content: Text(使用GetX管理的对话框), actions: [ TextButton( child: Text(关闭), onPressed: () Get.back(), ), ], ), barrierDismissible: false, );16.3 与Redux集成通过Redux action控制对话框// Action class ShowDialogAction { final Widget dialog; ShowDialogAction(this.dialog); } // Reducer AppState reducer(AppState state, dynamic action) { if (action is ShowDialogAction) { return state.copyWith(currentDialog: action.dialog); } return state; } // 在UI中显示 StoreConnectorAppState, Widget?( converter: (store) store.state.currentDialog, builder: (context, dialog) { return Stack( children: [ // 主界面内容 if (dialog ! null) dialog, ], ); }, )17. 对话框性能优化进阶17.1 延迟加载对话框内容对于复杂对话框内容使用FutureBuilder延迟加载AlertDialog( content: FutureBuilder( future: _loadDialogData(), builder: (context, snapshot) { if (snapshot.connectionState ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } return Text(snapshot.data.toString()); }, ), )17.2 对话框内存优化图片资源优化使用cacheHeight和cacheWidth限制对话框中的图片内存占用Image.network( https://example.com/image.jpg, cacheHeight: 200, cacheWidth: 200, )列表优化对于对话框中的长列表使用ListView.builder而不是Column17.3 对话框渲染性能分析使用WidgetsBinding分析对话框渲染性能void _showDialogWithProfile() { WidgetsBinding.instance.addPostFrameCallback((_) { final frameTiming WidgetsBinding.instance.renderViewElement!.debugDescribeLastFrame(); debugPrint(对话框渲染耗时: ${frameTiming.toString()}); }); showDialog(...); }18. 对话框安全最佳实践18.1 防止对话框劫持限制对话框显示频率DateTime? _lastDialogTime; void showSafeDialog(BuildContext context) { final now DateTime.now(); if (_lastDialogTime ! null now.difference(_lastDialogTime!) Duration(seconds: 1)) { return; } _lastDialogTime now; showDialog(...); }验证对话框上下文void showValidatedDialog(BuildContext context) { if (context.mounted ModalRoute.of(context)?.isCurrent true) { showDialog(...); } }18.2 敏感操作确认对于敏感操作实现二次确认void confirmSensitiveAction(BuildContext context) async { final confirmed await showDialogbool( context: context, builder: (context) AlertDialog( title: Text(确认敏感操作), content: Text(此操作将修改重要数据请输入密码确认), actions: [ TextField( obscureText: true, decoration: InputDecoration(labelText: 密码), ), TextButton( child: Text(取消), onPressed: () Navigator.pop(context, false), ), TextButton( child: Text(确认), onPressed: () { if (_validatePassword()) { Navigator.pop(context, true); } }, ), ], ), ); if (confirmed true) { _performSensitiveAction(); } }18.3 防止UI覆盖攻击确保关键对话框不会被其他UI元素覆盖showDialog( context: context, barrierColor: Colors.black54, barrierDismissible: false, useRootNavigator: true, // 使用根导航器确保在最上层显示 builder: (context) AlertDialog(...), );19. 对话框与导航深度集成19.1 对话框路由拦截在路由跳转前显示确认对话框Navigator.of(context).push( MaterialPageRoute( builder: (context) NextPage(), settings: RouteSettings(...), ), ).then((_) { // 路由返回后处理 }); // 在路由拦截器中 WillPopScope( onWillPop: () async { final shouldPop await showDialogbool( context: context, builder: (context) AlertDialog( title: Text(确认离开), content: Text(未保存的更改将丢失), actions: [ TextButton( child: Text(取消), onPressed: () Navigator.pop(context, false), ), TextButton( child: Text(确定), onPressed: () Navigator.pop(context, true), ), ], ), ); return shouldPop ?? false; }, child: ..., )19.2 嵌套对话框管理处理多层对话框的显示顺序void showNestedDialog(BuildContext context) { showDialog( context: context, builder: (context) AlertDialog( title: Text(第一层对话框), actions: [ TextButton( child: Text(显示第二层), onPressed: () { showDialog( context: context, builder: (innerContext) AlertDialog( title: Text(第二层对话框), content: Text(使用不同的BuildContext), actions: [ TextButton( child: Text(关闭), onPressed: () Navigator.pop(innerContext), ), ], ), ); }, ), ], ), ); }19.3 对话框与页面生命周期监听对话框显示/隐藏事件override void didChangeDependencies() { super.didChangeDependencies(); final isDialogVisible ModalRoute.of(context)?.isCurrent true; if (isDialogVisible) { // 对话框已显示 } else { // 对话框已隐藏 } }20. 对话框组件封装与复用20.1 基础对话框封装创建可复用的对话框组件class CustomDialog extends StatelessWidget { final String title; final String content; final VoidCallback? onConfirm; const CustomDialog({ required this.title, required this.content, this.onConfirm, }); static Futurebool? show({ required BuildContext context, required String title, required String content, VoidCallback? onConfirm, }) { return showDialogbool( context: context, builder: (context) CustomDialog(
返回列表