前言

Flutter是Google开发的开源UI工具包,支持用一套代码构建iOSAndroidWebWindowsmacOSLinux六大平台应用,实现"一次编写,多处运行"。

OpenHarmony是由开放原子开源基金会运营的分布式操作系统,为全场景智能设备提供统一底座,具有多设备支持、模块化设计、分布式能力和开源开放等特性。

Flutter for OpenHarmony技术方案使开发者能够:

  1. 复用Flutter现有代码(Skia渲染引擎、热重载、丰富组件库)
  2. 快速构建符合OpenHarmony规范的UI
  3. 降低多端开发成本
  4. 利用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,     // 与页面状态联动
)

注意事项:

  • 加载态禁用点击:isLoadingtrue 时禁用点击,业务侧仍需保证异步流程防重入。
  • 父容器约束:按钮使用 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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐