Flutter for OpenHarmony 实战:对话框(AlertDialog、SimpleDialog)的使用
提供页面级的渐变背景,并使用SafeArea保护内容不被系统区域遮挡。@overridecolors: [],),),// 在页面 Scaffold 的 body 中child: Center(/* 页面内容 */),),背景颜色较浅,主体组件建议使用深色文字或主题色强调对比度。若页面需要滚动,确保滚动视图位于child内部。无状态组件包裹,简单稳定;渐变参数可作为配置扩展。支持点击高亮与缩放反馈
前言
Flutter是Google开发的开源UI工具包,支持用一套代码构建iOS、Android、Web、Windows、macOS和Linux六大平台应用,实现"一次编写,多处运行"。
OpenHarmony是由开放原子开源基金会运营的分布式操作系统,为全场景智能设备提供统一底座,具有多设备支持、模块化设计、分布式能力和开源开放等特性。
Flutter for OpenHarmony技术方案使开发者能够:
- 复用Flutter现有代码(Skia渲染引擎、热重载、丰富组件库)
- 快速构建符合OpenHarmony规范的UI
- 降低多端开发成本
- 利用Dart生态插件资源加速生态建设
先看效果

在鸿蒙真机 上模拟器上成功运行后的效果

目录
下文只要按入口文件与组件模块进行代码分块解释,突出每个组件的开发重点、使用方法、注意事项与特殊逻辑。
1. 项目结构
项目主要代码位于 lib 目录:
lib/
├── main.dart # 程序入口与路由
├── pages/
│ └── dialog_demo_page.dart # 对话框演示页面
└── widgets/
├── cool_button.dart # 自定义按钮组件
├── cool_dialogs.dart # 对话框工具方法集合
└── gradient_background.dart # 渐变背景容器
关联文件参考:
- [main.dart](file:///d:/demo3/lib/main.dart)
- [dialog_demo_page.dart](file:///d:/demo3/lib/pages/dialog_demo_page.dart)
- [cool_button.dart](file:///d:/demo3/lib/widgets/cool_button.dart)
- [cool_dialogs.dart](file:///d:/demo3/lib/widgets/cool_dialogs.dart)
- [gradient_background.dart](file:///d:/demo3/lib/widgets/gradient_background.dart)
2. 程序入口 (main.dart)
职责:
- 初始化
MaterialApp,设置主题与路由。 - 将默认路由指向对话框演示页面。
关键代码与解释:
return MaterialApp(
title: 'Cool Dialogs Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple,
brightness: Brightness.light,
),
useMaterial3: true,
),
routes: {
'/dialogs': (_) => const DialogDemoPage(), // 定义命名路由
},
initialRoute: '/dialogs', // 初始路由
);
注意事项与特殊逻辑:
- 使用命名路由可便于后续模块扩展;初始路由通过
initialRoute控制。 - Material 3 启用后,组件默认风格会变化;自定义组件内部如使用
Theme.of(context),将自动适配主题色。
3. 自定义组件详解
3.1 GradientBackground (背景容器)
功能描述:
- 提供页面级的渐变背景,并使用
SafeArea保护内容不被系统区域遮挡。
核心代码与解释:
class GradientBackground extends StatelessWidget {
final Widget child;
const GradientBackground({super.key, required this.child});
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.blue.shade50,
Colors.purple.shade50,
],
),
),
child: SafeArea(child: child),
);
}
}
使用示例与解释(页面中包裹主体):
// 在页面 Scaffold 的 body 中
body: GradientBackground(
child: Center(/* 页面内容 */),
),
注意事项:
- 背景颜色较浅,主体组件建议使用深色文字或主题色强调对比度。
- 若页面需要滚动,确保滚动视图位于
child内部。
特殊逻辑说明:
- 无状态组件包裹,简单稳定;渐变参数可作为配置扩展。
3.2 CoolButton (自定义按钮)
功能描述:
- 支持点击高亮与缩放反馈、加载态切换、主题色渐变和阴影。
核心代码与解释:
class CoolButton extends StatefulWidget {
final String text;
final VoidCallback onPressed;
final bool isLoading;
// ...
}
class _CoolButtonState extends State<CoolButton> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _scaleAnimation;
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 120));
_scaleAnimation = Tween<double>(begin: 1.0, end: 0.92).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
}
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: widget.isLoading ? null : widget.onPressed,
onHighlightChanged: (h) { h ? _controller.forward() : _controller.reverse(); },
borderRadius: BorderRadius.circular(25),
child: ScaleTransition(
scale: _scaleAnimation,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: double.infinity,
height: 55,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: widget.isLoading
? [Colors.grey.shade400, Colors.grey.shade500]
: [Theme.of(context).primaryColor, Theme.of(context).primaryColor.withBlue(200)],
),
borderRadius: BorderRadius.circular(25),
boxShadow: [/* 阴影随加载态变化 */],
),
child: Center(
child: widget.isLoading
? const CircularProgressIndicator(color: Colors.white, strokeWidth: 2)
: Text(widget.text, style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
),
),
),
),
);
}
}
使用示例与解释(页面中触发操作):
CoolButton(
text: 'AlertDialog',
onPressed: _showAlert, // 触发对话框
isLoading: _loading, // 与页面状态联动
)
注意事项:
- 加载态禁用点击:
isLoading为true时禁用点击,业务侧仍需保证异步流程防重入。 - 父容器约束:按钮使用
double.infinity宽度,应置于有宽度约束的布局下(如Column内)。 - 动画控制器释放:在
dispose中释放AnimationController。
特殊逻辑说明:
- 使用
InkWell的高亮与水波纹配合ScaleTransition,形成自然点击反馈。 - 渐变与阴影根据加载态切换,确保视觉状态一致。
3.3 CoolDialogs (对话框工具集)
包含两类对话框方法与一个选项模型:
showCoolAlertDialog<T>:确认型对话框,返回true/false。showCoolSimpleDialog<T>:选项型对话框,返回所选项的value。DialogOption<T>:用于SimpleDialog的选项描述。
关键实现与解释:
Future<T?> showCoolAlertDialog<T>({ required BuildContext context, required String title, required String content, ... }) {
return showGeneralDialog<T>(
context: context,
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.35),
transitionDuration: const Duration(milliseconds: 320),
pageBuilder: (_, __, ___) { /* 渐变卡片 + 模糊背景 */ },
transitionBuilder: (_, animation, __, child) {
final fade = CurvedAnimation(parent: animation, curve: Curves.easeOut);
final scale = Tween<double>(begin: 0.94, end: 1.0).animate(fade);
final slide = Tween<Offset>(begin: const Offset(0, 0.06), end: Offset.zero).animate(fade);
return FadeTransition(opacity: fade, child: SlideTransition(position: slide, child: ScaleTransition(scale: scale, child: child)));
},
);
}
Future<T?> showCoolSimpleDialog<T>({ required BuildContext context, required String title, required List<DialogOption<T>> options }) {
return showGeneralDialog<T>(
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.35),
transitionDuration: const Duration(milliseconds: 300),
pageBuilder: (_, __, ___) { /* 选项列表卡片 */ },
transitionBuilder: (_, animation, __, child) {
final fade = CurvedAnimation(parent: animation, curve: Curves.easeOut);
final slide = Tween<Offset>(begin: const Offset(0, 0.08), end: Offset.zero).animate(fade);
return FadeTransition(opacity: fade, child: SlideTransition(position: slide, child: child));
},
);
}
使用示例与解释(页面中调用对话框):
// 确认型
final ok = await showCoolAlertDialog<bool>(
context: context,
title: '提示',
content: '这是一个 AlertDialog,是否继续?',
confirmText: '继续',
cancelText: '取消',
);
if (ok == true) { /* 用户点击继续 */ }
// 选项型
final action = await showCoolSimpleDialog<String>(
context: context,
title: '选择一种操作',
options: const [
DialogOption(label: '复制', icon: Icons.copy_rounded, value: 'copy'),
DialogOption(label: '分享', icon: Icons.share_rounded, value: 'share'),
DialogOption(label: '收藏', icon: Icons.bookmark_rounded, value: 'fav'),
],
);
if (action != null) { /* 根据 action 执行操作 */ }
注意事项:
showGeneralDialog默认可点击遮罩关闭(barrierDismissible: true),如需强制选择可设置为false。- 返回值通过
Navigator.pop(result)传递;调用方需根据返回类型做空值判定。 - 模糊与阴影效果在低端设备可能带来轻微性能开销,建议控制过渡时长与模糊强度。
特殊逻辑说明:
BackdropFilter+ImageFilter.blur实现模糊背景,增强层次感。- 过渡组合(Fade + Slide + Scale)让弹出更自然,避免突兀。
DialogOption<T>作为纯数据模型,便于复用与类型安全。
关联代码参考:
- [showCoolAlertDialog](file:///d:/demo3/lib/widgets/cool_dialogs.dart#L4-L127)
- [showCoolSimpleDialog](file:///d:/demo3/lib/widgets/cool_dialogs.dart#L129-L222)
- [DialogOption](file:///d:/demo3/lib/widgets/cool_dialogs.dart#L224-L229)
4. 业务页面 (DialogDemoPage)
职责:
- 组织页面结构与渐入动画。
- 通过按钮触发两类对话框,并将结果通过
SnackBar反馈。
状态与动画配置(initState):
_controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 900));
_fade = CurvedAnimation(parent: _controller, curve: const Interval(0.0, 0.6, curve: Curves.easeOut));
_slide = Tween<Offset>(begin: const Offset(0, 0.08), end: Offset.zero).animate(
CurvedAnimation(parent: _controller, curve: const Interval(0.0, 0.6, curve: Curves.easeOutCubic)),
);
_controller.forward();
操作与反馈(Alert 与 Simple):
Future<void> _showAlert() async {
setState(() => _loading = true);
await Future.delayed(const Duration(milliseconds: 300));
setState(() => _loading = false);
final result = await showCoolAlertDialog<bool>(/* ... */);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(result == true ? '选择了继续' : '选择了取消')),
);
}
Future<void> _showSimple() async {
setState(() => _loading = true);
await Future.delayed(const Duration(milliseconds: 300));
setState(() => _loading = false);
final result = await showCoolSimpleDialog<String>(/* ... */);
if (!mounted) return;
if (result != null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('选择了:$result')));
}
}
页面布局(渐变背景 + 动画 + 按钮):
return Scaffold(
body: GradientBackground(
child: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: FadeTransition(
opacity: _fade,
child: SlideTransition(
position: _slide,
child: Column(
children: [
CoolButton(text: 'AlertDialog', onPressed: _showAlert, isLoading: _loading),
const SizedBox(height: 12),
CoolButton(text: 'SimpleDialog', onPressed: _showSimple, isLoading: _loading),
],
),
),
),
),
),
),
);
注意事项:
mounted判定:异步完成后需判定页面是否仍在树中,避免在销毁后setState。- 轻量加载态:按钮与页面的
_loading状态联动,避免重复弹窗。 - 动画分段曲线:使用
Interval与不同曲线组合让入场更柔和。
特殊逻辑说明:
- 将对话框调用封装在独立方法中,便于维护与测试。
SnackBar设置了圆角与主题色,保证与整体风格一致。
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)