原创力作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

flutter3-macOS桌面端os系统|flutter3.x+window_manager仿mac桌面管理的更多相关文章

  1. [资源共享]C#+AE构建GIS桌面端应用系统框架-全代码

    转自:http://www.cnblogs.com/gispeng/archive/2008/10/06/1304534.html    [资源共享]C#+AE构建GIS桌面端应用系统框架-全代码 ( ...

  2. Electron-Vite2-MacUI桌面管理框架|electron13+vue3.x仿mac桌面UI

    基于vue3.0.11+electron13仿制macOS桌面UI管理系统ElectronVue3MacUI. 前段时间有分享一个vue3结合electron12开发后台管理系统项目.今天要分享的是最 ...

  3. VMWare15 安装 Mac OS 系统

    文章目录VMWare15 安装 Mac OS 系统安装环境工具准备准备工作MAC虚拟机设置启动MAC前准备工作安装系统安装VMware Tool注意事项参考链接安装环境WIN10VMware Work ...

  4. Google工程师打造Remix OS系统 桌面版安卓下载

    三位前Google工程师打造的Remix OS系统终于来到了PC桌面上,现已可以下载尝鲜. Remix OS for PC基于Android-x86项目,由安卓5.1 Lollipop深度定制而来,不 ...

  5. Electron-Vue3-Vadmin后台系统|vite2+electron桌面端权限管理系统

    基于vite2.x+electron12桌面端后台管理系统Vite2ElectronVAdmin. 继上一次分享vite2整合electron搭建后台框架,这次带来的是最新开发的跨桌面中后台权限管理系 ...

  6. 使用JS开发桌面端应用程序NW.js-1-Menu菜单的使用小记

    前言 本文主要内容为nw.js官方文档中没有提到,而在实际入手开发过程中才碰到的问题以及经验的汇总. 详情请查看官方文档:http://docs.nwjs.io/en/latest/Reference ...

  7. python桌面端开发手记(序列化、压缩包、加密、图形界面GUI)

    0x00   前段时间接到一个小项目是给某行业内部开发离线桌面端,业务流实现上总体分信息录入.加密导出.因为是win桌面端,所以老板说依托Access用VBA做,我据理力争了一下.之前就是用Acces ...

  8. Flutter Windows 桌面端支持进入稳定版

    Flutter 创建伊始,我们就致力于打造一个能够构建精美的.可高度定制的.并且可以编译为机器码的跨平台应用解决方案,以充分发挥设备底层硬件的全部图形渲染能力.今天,Flutter 对 Windows ...

  9. Tauri-Vue3桌面端聊天室|tauri+vite3仿微信|tauri聊天程序EXE

    基于tauri+vue3.js+vite3跨桌面端仿微信聊天实例TauriVue3Chat. tauri-chat 运用最新tauri+vue3+vite3+element-plus+v3layer等 ...

  10. 熊猫猪新系统測试之二:Mac OS X 10.10 优胜美地

    在第一篇windows 10技术预览版測试之后.本猫为大家呈现还有一个刚刚才更新的mac操作系统:"优胜美地".苹果相同一改以猫科动物为代号命名的传统.在10.9的Maverick ...

随机推荐

  1. 手把手教你python数据处理项目——探索ebay汽车销售数据

      探索Ebay汽车销售数据 一.实验目的 1. 熟悉清理数据的流程: 2. 分析Ebay二手车销售数据: 3. 了解jupyter notebook为pandas提供的一些独特特性. 二.实验开发环 ...

  2. 影刀rpa:关于if单条件切换到多条件时的不便之处

    现有需求,只判断一个条件是否满足即可,但随着后续业务开发,这里得if就需要判断多个条件,此时要是想将if单条件改为多条件的话,就得先拉一个if多条件的指令,然后再将if单条件中的语句全部移动到if多条 ...

  3. C语言趣味编程之抓交通肇事犯

    include <stdio.h> main() { int i, j, k, temp;//i,j,k,分别表示前两位车牌号.后两位车牌号和车牌号,temp为验证是否车牌号为某个数的平方 ...

  4. Seata的技术调研

    引子 本文不剖析业内分布式组件,只剖析seata这一组件的技术调研.看看是否存在接入价值. 一.概述 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata ...

  5. crc16校验C语言源码实例解析

    一 概念: 循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC.它是利用除法及余数的原理来作错误侦测(Error Detecting)的.实际应用时,发送装置计算出 ...

  6. 泰凌微TLSR8258芯片解决方案开发之串口打印级别设置

    一  TRSR8258简介 该芯片是泰凌微推出来的一款纯ble的芯片,接口丰富,功耗低,资源丰富,非常适合做可穿戴物联网设备,笔者拿这颗芯片做了不少方案,感觉非常好用,所以这里写一下使用心得. 二 串 ...

  7. python读取文本多行合并一行

    # 需要合并的行数 col = 4 # 创建新文件 nf = open("*.txt", "w+") # 读取初始文件 with open("*.tx ...

  8. 反编译和逆向出现:java.lang.VerifyError(新问题样本)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  9. 【atcoder abc281_d】动态规划

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @ ...

  10. Kotlin 协程基础使用学习

    原文: Kotlin 协程基础使用学习-Stars-One的杂货小窝 本篇阅读可能需要以下知识,否则可能阅读会有些困难 客户端开发基础(Android开发或JavaFx开发) Java多线程基础 ko ...