首页 > 其他分享 >flutter3-macOS桌面端os系统|flutter3.x+window_manager仿mac桌面管理

flutter3-macOS桌面端os系统|flutter3.x+window_manager仿mac桌面管理

时间:2024-04-12 21:45:23浏览次数:34  
标签:macOS const title item flutter3 dialog child 桌面 imgico

原创力作flutter3+getX+window_manager仿Mac桌面系统平台Flutter-MacOS

flutter3_macui基于最新跨端技术flutter3.19+dart3.3+window_manager+system_tray构建的一款桌面端仿MacOS风格os系统项目。支持自定义主题换肤、毛玻璃虚化背景、程序坞Dock菜单多级嵌套+自由拖拽排序、可拖拽路由弹窗等功能。

FlutterMacOS系统是自研原创多级菜单、支持可拖拽弹窗打开路由页面模板。

使用技术

  • 编辑器:vscode
  • 框架技术:Flutter3.19.2+Dart3.3.0
  • 窗口管理:window_manager^0.3.8
  • 路由/状态管理:get^4.6.6
  • 缓存服务:get_storage^2.1.1
  • 拖拽排序:reorderables^0.6.0
  • 图表组件:fl_chart^0.67.0
  • 托盘管理:system_tray^2.0.3

功能特色

  1. 桌面菜单支持JSON配置/二级弹窗菜单
  2. 采用ios虚化毛玻璃背景效果
  3. 经典程序坞Dock菜单
  4. 程序坞Dock菜单可拖拽式排序、支持二级弹窗式菜单
  5. 丰富视觉效果,自定义桌面主题换肤背景
  6. 可视化多窗口路由,支持弹窗方式打开新路由页面
  7. 自定义路由弹窗支持全屏、自由拖拽
  8. 支持macOS和windows 11两种风格Dock菜单

项目结构

通过 flutter create flutter_macos 命令即可快速创建一个flutter空项目模板。

通过 flutter run -d windows 命令即可运行到windows桌面。

在开始开发项目之前,需要自己配置好flutter sdk开发环境。具体配置大家可以去官网查阅资料,有详细的配置步骤。

Flutter3桌面os布局模板

桌面os布局整体分为顶部导航条+桌面菜单+底部Dock菜单三大模块。

return Scaffold(
  key: scaffoldKey,
  body: Container(
    // 背景图主题
    decoration: skinTheme(),
    // DragToResizeArea自定义缩放窗口
    child: DragToResizeArea(
      child: Flex(
        direction: Axis.vertical,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 导航栏
          WindowTitlebar(
            onDrawer: () {
              // 自定义打开右侧drawer
              scaffoldKey.currentState?.openEndDrawer();
            },
          ),

          // 桌面区域
          Expanded(
            child: GestureDetector(
              child: Container(
                color: Colors.transparent,
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Expanded(
                      child: GestureDetector(
                        child: const WindowDesktop(),
                        onSecondaryTapDown: (TapDownDetails details) {
                          posDX = details.globalPosition.dx;
                          posDY = details.globalPosition.dy;
                        },
                        onSecondaryTap: () {
                          debugPrint('桌面图标右键');
                          showDeskIconContextmenu();
                        },
                      ),
                    ),
                  ],
                ),
              ),
              onSecondaryTapDown: (TapDownDetails details) {
                posDX = details.globalPosition.dx;
                posDY = details.globalPosition.dy;
              },
              onSecondaryTap: () {
                debugPrint('桌面右键');
                showDeskContextmenu();
              },
            ),
          ),

          // Dock菜单
          settingController.settingData['dock'] == 'windows' ?
          const WindowTabbar()
          :
          const WindowDock()
          ,
        ],
      ),
    ),
  ),
  endDrawer: Drawer(
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0.0)),
    width: 300,
    child: const Settings(),
  ),
);

Flutter3实现程序坞Dock菜单

底部Dock菜单支持macOSwindows11两种风格。采用毛玻璃虚化背景、支持拖拽排序二级弹窗菜单

鼠标滑过图标,该图标带动画效果放大,采用 MouseRegion 和 ScaleTransition 缩放动画组件一起实现功能。

// 动画控制器
late AnimationController controller = AnimationController(duration: const Duration(milliseconds: 300), vsync: this);
MouseRegion(
  cursor: SystemMouseCursors.click,
  onEnter: (event) {
    setState(() {
      hoveredIndex = index;
    });
    controller.forward(from: 0.0);
  },
  onExit: (event) {
    setState(() {
      hoveredIndex = -1;
    });
    controller.stop();
  },
  child: GestureDetector(
    onTapDown: (TapDownDetails details) {
      anchorDx = details.globalPosition.dx;
    },
    onTap: () {
      if(item!['children'] != null) {
        showDockDialog(item!['children']);
      }
    },
    // 缩放动画
    child: ScaleTransition(
      alignment: Alignment.bottomCenter,
      scale: hoveredIndex == index ? 
      controller.drive(Tween(begin: 1.0, end: 1.5).chain(CurveTween(curve: Curves.easeOutCubic)))
      :
      Tween(begin: 1.0, end: 1.0).animate(controller)
      ,
      child: UnconstrainedBox(
        child: Stack(
          alignment: AlignmentDirectional.topCenter,
          children: [
            // tooltip提示
            Visibility(
              visible: hoveredIndex == index && !draggable,
              child: Positioned(
                top: 0,
                child: SizedOverflowBox(
                  size: Size.zero,
                  child: Container(
                    alignment: Alignment.center,
                    padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 1.0),
                    margin: const EdgeInsets.only(bottom: 20.0),
                    decoration: BoxDecoration(
                      color: Colors.black54,
                      borderRadius: BorderRadius.circular(3.0),
                    ),
                    child: Text('${item!['tooltip']}', style: const TextStyle(color: Colors.white, fontSize: 8.0, fontFamily: 'arial')),
                  ),
                ),
              ),
            ),
            // 图片/图标
            item!['children'] != null ?
            thumbDock(item!['children'])
            :
            SizedBox(
              height: 35.0,
              width: 35.0,
              child: item!['type'] != null && item!['type'] == 'icon' ? 
              IconTheme(
                data: const IconThemeData(color: Colors.white, size: 32.0),
                child: item!['imgico'],
              )
              :
              Image.asset('${item!['imgico']}')
              ,
            ),
            // 圆点
            Visibility(
              visible: item!['active'] != null,
              child: Positioned(
                bottom: 0,
                child: SizedOverflowBox(
                  size: Size.zero,
                  child: Container(
                    margin: const EdgeInsets.only(top: 2.0),
                    height: 4.0,
                    width: 4.0,
                    decoration: BoxDecoration(
                      color: Colors.black87,
                      borderRadius: BorderRadius.circular(10.0),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    ),
  ),
)

菜单JSON格式配置项,图标支持Icon图标Image图片

List dockList = [
  {'tooltip': 'Flutter3.19', 'imgico': 'assets/images/logo.png'},
  {'tooltip': 'Safari', 'imgico': 'assets/images/mac/safari.png', 'active': true},
  {
    'tooltip': 'Launchpad',
    'imgico': 'assets/images/mac/launchpad.png',
    'children': [
      {'tooltip': 'Podcasts', 'imgico': 'assets/images/mac/podcasts.png'},
      {'tooltip': 'Quicktime', 'imgico': 'assets/images/mac/quicktime.png'},
      {'tooltip': 'Notes', 'imgico': 'assets/images/mac/notes.png'},
      {'tooltip': 'Reminder', 'imgico': 'assets/images/mac/reminders.png'},
      {'tooltip': 'Calc', 'imgico': 'assets/images/mac/calculator.png'},
    ]
  },
  {'tooltip': 'Appstore', 'imgico': 'assets/images/mac/appstore.png',},
  {'tooltip': 'Messages', 'imgico': 'assets/images/mac/messages.png', 'active': true},

  {'type': 'divider'},
  
  ...
  
  {'tooltip': 'Recycle Bin', 'imgico': 'assets/images/mac/bin.png'},
];

二级菜单采用showDialog组件实现三列排版,支持背景虚化、可滚动列表。定位采用Positioned组件实现功能。

void showDockDialog(data) {
  anchorDockOffset();
  showDialog(
    context: context,
    barrierColor: Colors.transparent,
    builder: (context) {
      return Stack(
        children: [
          Positioned(
            top: anchorDy - 210,
            left: anchorDx - 120,
            width: 240.0,
            height: 210,
            child: ClipRRect(
              borderRadius: BorderRadius.circular(16.0),
              child: BackdropFilter(
                filter: ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0),
                child: Container(
                  padding: const EdgeInsets.symmetric(vertical: 10.0),
                  decoration: const BoxDecoration(
                    backgroundBlendMode: BlendMode.overlay,
                    color: Colors.white,
                  ),
                  child: ListView(
                    children: [
                      Container(
                        padding: const EdgeInsets.symmetric(horizontal: 10.0,),
                        child: Wrap(
                          runSpacing: 5.0,
                          spacing: 5.0,
                          children: List.generate(data.length, (index) {
                            final item = data[index];
                            return MouseRegion(
                              cursor: SystemMouseCursors.click,
                              child: GestureDetector(
                                child:  Column(
                                  children: [
                                    // 图片/图标
                                    SizedBox(
                                      height: 40.0,
                                      width: 40.0,
                                      child: item!['type'] != null && item!['type'] == 'icon' ? 
                                      IconTheme(
                                        data: const IconThemeData(color: Colors.black87, size: 35.0),
                                        child: item!['imgico'],
                                      )
                                      :
                                      Image.asset('${item!['imgico']}')
                                      ,
                                    ),
                                    SizedBox(
                                      width: 70,
                                      child: Text(item['tooltip'], style: const TextStyle(color: Colors.black87, fontSize: 12.0), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,),
                                    )
                                  ],
                                ),
                                onTap: () {
                                  // ...
                                },
                              ),
                            );
                          }),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ],
      );
    },
  );
}

Flutter实现桌面多级菜单

桌面菜单采用 Wrap 组件竖向排列显示。

@override
Widget build(BuildContext context) {
  return Container(
    padding: const EdgeInsets.all(10.0),
    child: Wrap(
      direction: Axis.vertical,
      spacing: 5.0,
      runSpacing: 5.0,
      children: List.generate(deskList.length, (index) {
        final item = deskList[index];
        return MouseRegion(
          cursor: SystemMouseCursors.click,
          onEnter: (event) {
            setState(() {
              hoveredIndex = index;
            });
          },
          onExit: (event) {
            setState(() {
              hoveredIndex = -1;
            });
          },
          child: GestureDetector(
            onTapDown: (TapDownDetails details) {
              anchorDx = details.globalPosition.dx;
              anchorDy = details.globalPosition.dy;
            },
            onTap: () {
              if(item!['children'] != null) {
                showDeskDialog(item!['children']);
              }else {
                showRouteDialog(item);
              }
            },
            child: Container(
              ...
            ),
          ),
        );
      }),
    ),
  );
}

桌面菜单缩略二级弹窗菜单和Dock菜单实现思路差不多。点击桌面菜单通过弹窗方式显示配置的页面。

/**
  桌面弹窗式路由页面  Q:282310962
*/
void showRouteDialog(item) async {
  // 链接
  if(item!['link'] != null) {
    await launchUrl(Uri.parse(item!['link']));
    return;
  }
  // 弹窗图标
  Widget dialogIcon() {
    if(item!['type'] != null && item!['type'] == 'icon') {
      return IconTheme(
        data: const IconThemeData(size: 16.0),
        child: item!['imgico'],
      );
    }else {
      return Image.asset('${item!['imgico']}', height: 16.0, width: 16.0, fit: BoxFit.cover);
    }
  }

  // Fdialog参数
  dynamic dialog = item!['dialog'] ?? {};

  navigator?.push(FdialogRoute(
    child: Fdialog(
      // 标题
      title: dialog!['title'] ?? Row(
        children: [
          dialogIcon(),
          const SizedBox(width: 5.0,),
          Text('${item!['title']}',),
        ],
      ),
      // 内容
      content: dialog!['content'] ?? ListView(
        padding: const EdgeInsets.all(10.0),
        children: [
          item!['component'] ?? const Center(child: Column(children: [Icon(Icons.layers,), Text('Empty~'),],)),
        ],
      ),
      titlePadding: dialog!['titlePadding'], // 标题内间距
      backgroundColor: dialog!['backgroundColor'] ?? Colors.white.withOpacity(.85), // 弹窗背景色
      barrierColor: dialog!['barrierColor'], // 弹窗遮罩层颜色
      offset: dialog!['offset'], // 弹窗位置(坐标点)
      width: dialog!['width'] ?? 800, // 宽度
      height: dialog!['height'] ?? 500, // 高度
      radius: dialog!['radius'], // 圆角
      fullscreen: dialog!['fullscreen'] ?? false, // 是否全屏
      maximizable: dialog!['maximizable'] ?? true, // 是否显示最大化按钮
      closable: dialog!['closable'] ?? true, // 是否显示关闭按钮
      customClose: dialog!['customClose'], // 自定义关闭按钮
      closeIcon: dialog!['closeIcon'], // 自定义关闭图标
      actionColor: dialog!['actionColor'], // 右上角按钮组颜色
      actionSize: dialog!['actionSize'], // 右上角按钮组大小
      draggable: dialog!['draggable'] ?? true, // 是否可拖拽
      destroyOnExit: dialog!['destroyOnExit'] ?? false, // 鼠标滑出弹窗是否销毁关闭
    ),
  ));
}

桌面菜单json配置和Dock菜单配置差不多,只不过多了componentdialog两个参数。component参数是弹窗打开需要显示的页面,dialog是自定义弹窗配置参数。

List deskList = [
  {'title': 'Flutter3.19', 'imgico': 'assets/images/logo.png', 'link': 'https://flutter.dev/'},
  {
    'title': '首页', 'imgico': const Icon(Icons.home_outlined), 'type': 'icon',
    'component': const Home(),
    'dialog': {
      'fullscreen': true
    }
  },
  {
    'title': '工作台', 'imgico': const Icon(Icons.poll_outlined), 'type': 'icon',
    'component': const Dashboard(),
  },
  {
    'title': '组件',
    'imgico': const Icon(Icons.apps),
    'type': 'icon',
    'children': [
      {'title': 'Mail', 'imgico': 'assets/images/mac/mail.png'},
      {'title': 'Info', 'imgico': 'assets/images/mac/info.png'},
      {'title': 'Editor', 'imgico': 'assets/images/mac/scripteditor.png'},
      {'title': '下载', 'imgico': const Icon(Icons.download_outlined), 'type': 'icon'},
      {'title': 'Bug统计', 'imgico': const Icon(Icons.bug_report_outlined), 'type': 'icon'},
      {'title': '计算器', 'imgico': const Icon(Icons.calculate), 'type': 'icon'},
      {'title': '图表', 'imgico': const Icon(Icons.bar_chart), 'type': 'icon'},
      {'title': '打印', 'imgico': const Icon(Icons.print), 'type': 'icon'},
      {'title': '站内信', 'imgico': const Icon(Icons.campaign), 'type': 'icon'},
      {'title': '云存储', 'imgico': const Icon(Icons.cloud_outlined), 'type': 'icon'},
      {'title': '裁剪', 'imgico': const Icon(Icons.crop_outlined), 'type': 'icon'},
    ]
  },
  {
    'title': '私密空间', 'imgico': const Icon(Icons.camera_outlined), 'type': 'icon',
    'component': const Uzone(),
  },
  
  ...
  
  {
    'title': '公众号', 'imgico': const Icon(Icons.qr_code), 'type': 'icon',
    'dialog': {
      'title': const Text('QRcode', style: TextStyle(color: Colors.white60, fontSize: 14.0, fontFamily: 'arial')),
      'content': Padding(
        padding: const EdgeInsets.all(10.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Image.asset('assets/images/qrcode_white.png', height: 120.0, fit: BoxFit.contain,),
            const Spacer(),
            const Text('扫一扫,关注公众号', style: TextStyle(color: Colors.white60, fontSize: 12.0,),),
          ],
        ),
      ),
      'backgroundColor': const Color(0xff07c160),
      'actionColor': Colors.white54,
      'width': 300,
      'height': 220,
      'maximizable': false,
      'closable': true,
      'draggable': true,
    }
  },
];

好了,综上就是flutter3+window_manager实战桌面端仿MacOS系统的一些分享,希望对大家有所帮助!

附上最近两个实例项目

https://www.cnblogs.com/xiaoyan2017/p/17938517

https://www.cnblogs.com/xiaoyan2017/p/18048244

 

标签:macOS,const,title,item,flutter3,dialog,child,桌面,imgico
From: https://www.cnblogs.com/xiaoyan2017/p/18132176

相关文章

  • Intel MacBook Pro+macOS 14配置Games101实验环境
    参考:求一个games101图形学课程的环境配置教程,最好能够简单易懂,CSDN教程根本看不懂什么意思?-不泊的回答-知乎https://www.zhihu.com/question/459126051/answer/3420947842macos现在怎么装homebrew?-MyloZ的回答-知乎https://www.zhihu.com/question/340411846/answe......
  • 基于 Scriptable 从零开始美化iOS桌面(集合篇)
    Scriptable脚本合集iOS桌面组件神器(Scriptable)原创脚本,精美作品收集、分享!如果喜欢,欢迎点个⭐️Star⭐️给予小支持,感谢您的使用!喜欢这个项目?有好的脚本?请考虑留言来帮助完善它!如果您使用过程中发现有问题或可以改进的流程,请提出Issue或Pullrequest!......
  • Python - [06] 桌面开发
     一、安装工具安装PyQt6和pyqt6-toolspipinstallPyQt6-ihttps://pypi.tuna.tsinghua.edu.cn/simplepipinstallpyqt6-tools-ihttps://pypi.tuna.tsinghua.edu.cn/simple //TODO       — 要养成终生学习的习惯— ......
  • vmware安装macos提示客户机操作系统已禁用 CPU。请关闭或重置虚拟机
    客户机操作系统已禁用CPU。请关闭或重置虚拟机。这是AMD电脑的VMware安装macOS出现的错误我们需要在虚拟机运行之前打开虚拟机安装目录自动生成的macOSxxxx(你选择安装的版本号).vmx只需要在末尾添加:smc.version="0"cpuid.0.eax="0000:0000:0000:0000:0000:0000:0000:......
  • 共享云桌面和虚拟云桌面优劣势对比分析
    随着云计算技术的不断发展,共享云桌面和虚拟云桌面成为了企业信息化建设的热门选择。共享云桌面和虚拟云桌面这两种技术各有优劣势,下面我们将对它们进行对比分析。首先,我们来了解一下共享云桌面的优势。共享云桌面是指多个用户通过云平台共享同一台物理服务器的计算资源,从而实......
  • Burp Suite Professional 2024.3.1 for macOS x64 & ARM64 - 领先的 Web 渗透测试软件
    BurpSuiteProfessional2024.3.1formacOSx64&ARM64-领先的Web渗透测试软件世界排名第一的Web渗透测试工具包请访问原文链接:BurpSuiteProfessional2024.3.1formacOSx64&ARM64-领先的Web渗透测试软件,查看最新版。原创作品,转载请保留出处。作者主页:sysin......
  • Burp Suite Professional 2024.3.1 (macOS, Linux, Windows) - Web 应用安全、测试和
    BurpSuiteProfessional2024.3.1(macOS,Linux,Windows)-Web应用安全、测试和扫描BurpSuiteProfessional,Test,find,andexploitvulnerabilities.请访问原文链接:BurpSuiteProfessional2024.3.1(macOS,Linux,Windows)-Web应用安全、测试和扫描,查看最新版。......
  • c# 桌面程序配置存储类
    publicstaticclassSettingHelper{privatestaticstringgetConfigPath(){varconfigFilePath=AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;vardir=Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder......
  • 【macOS】重置Finder窗口位置信息 & 大小信息
    ✨重置Finder窗口位置信息重置Finder窗口位置信息的shell脚本如下使用如下命令新建reset-window-position.sh文件并使用vim编辑touchreset-window-position.shvimreset-window-position.sh在reset-window-position.sh中写入以下内容#!/bin/zsh#输入应用名称echo"请......
  • 在 macOS 上安装 Subversion(SVN)
    在macOS上安装Subversion(SVN)要在macOS上安装Subversion(SVN),可以通过几种方式之一来安装它。以下是两种主要方法:通过Homebrew安装首先,确保已经安装了Homebrew。如果没有,请前往Homebrew官网遵循指示安装。打开终端应用程序。运行以下命令来安装Subversion:br......