原创力作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. SpringCloud zookeeper和consul 的介绍和基本搭建

    1. Spring Cloud 集成 zookeeper Spring Cloud 集成了 zookeeper ,通过一些简单的注释,就可以快速注册到zookeeper 服务中 并且支持Spring ...

  2. 制作B站直播简介

    本文只用于个人总结备份,如果对你有帮助就更好了. 准备工作 准备好简介要用的的背景图.头像图,上传到图床生成图片链接. 简介的内容可分为主播简介.直播时间.直播内容.联系方式,内容根据实际需要修改,需 ...

  3. python学习笔记(4):面向对象

    面向对象 定义 class Student(被继承类): def __init__(self, xx, xxx): #构造函数 类方法的第一个参数一定是self.除此之外和普通函数并没有区别.同样可以 ...

  4. 35_音视频播放器_seek&暂停

    目录 一.实现seek功能 二.解决点击seek操作时会出现画面快速闪过 三.实现暂停功能 3.1.音频暂停 3.2.视频暂停 一.实现seek功能 我们主要是使用ffmpeg的av_seek_fra ...

  5. Android端Charles抓包

    目录介绍 01.下载安装 02.抓包代理设置 03.抓包Https操作 04.抓包原理介绍 05.抓包数据介绍 06.常见问题总结 07.Android拦截抓包 01.下载安装 下载地址(下载对应的平 ...

  6. Android组件化开发实践和案例分享

    目录介绍 1.为什么要组件化 1.1 为什么要组件化 1.2 现阶段遇到的问题 2.组件化的概念 2.1 什么是组件化 2.2 区分模块化与组件化 2.3 组件化优势好处 2.4 区分组件化和插件化 ...

  7. 记录-记一次不规范使用key引发的惨案

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 平时在使用v-for的时候,一般会要求传入key,有没有像我一样的小伙伴,为了省心,直接传索引index,貌似也没有遇到过什么问题, ...

  8. ArcMap的mxd文件没有数据、显示感叹号怎么办?

      本文介绍在ArcMap软件中,导入.mxd地图文档文件后图层出现感叹号.地图显示空白等情况的解决办法.   在ArcMap软件使用过程中,我们经常会需要将包含有多个图层的.mxd地图文档文件导入软 ...

  9. FTP上传中文文件,内容乱码

    记录一下: spring boot 程序 ftp上传中文文件,内容乱码. 1.刚开始程序部署在Windows平台上测试,发现上传后的文件内容是乱码,查看文件编码格式是ANSI(Windows下文本文件 ...

  10. QT数据库学习笔记

    简介 QT通过模块化管理,对于某种模块需要添加对应的模块实现.QT SQL也是需要增加对应的模块来实现.QT数据库的层次关系为: 驱动层:数据库到SQL语言之间的桥梁 SQL API层: SQL语句的 ...