找回密码
 立即注册
首页 业界区 业界 最新研发flutter3.27+bitsdojo_window+getx客户端仿微信 ...

最新研发flutter3.27+bitsdojo_window+getx客户端仿微信聊天Exe应用

靳谷雪 13 小时前
2025跨平台Flutter3+Dart3+Getx仿微信电脑端Exe聊天系统Flutter3-WinChat
flutter3_winchat:基于最新跨平台框架flutter3.27+dart3.6+getx+bitsdojo_window+media_kit+system_tray搭建桌面客户端仿微信聊天exe实例。整合了聊天功能、联系人、收藏、朋友圈、小视频、我的等模块。
1.png

技术栈


  • 开发工具:Vscode
  • 技术框架:Flutter3.27.1+Dart3.6.0
  • 窗口管理:bitsdojo_window: ^0.1.6
  • 托盘图标:system_tray: ^2.0.3
  • 路由/状态管理:get: ^4.7.2
  • 本地存储:get_storage: ^2.1.1
  • 图片预览:photo_view: ^0.15.0
  • 网址预览:url_launcher: ^6.3.1
  • 视频组件:media_kit: ^1.2.0
  • 文件选择器:file_picker: ^10.2.0
  • 富文本编辑器:fleather: ^1.22.0
2.gif

3.gif

项目框架结构

4.png

flutter3-winchat电脑端聊天项目已经更新到我的原创作品集。

Flutter3.27+bitsdojo_window仿微信客户端聊天Exe
5.png

6.png

7.png

8.png

9.png

10.png

11.png

12.png

13.png

14.png

15.png

16.png

17.png

18.png

19.png

20.png

21.png

22.png

23.png

24.png

25.png

26.png

27.png

28.png

29.png

30.png

31.png

32.png

33.png

项目入口配置main.dart
  1. import 'dart:io';
  2. import 'package:flutter/material.dart';
  3. import 'package:bitsdojo_window/bitsdojo_window.dart';
  4. import 'package:get/get.dart';
  5. import 'package:get_storage/get_storage.dart';
  6. import 'package:media_kit/media_kit.dart';
  7. import 'package:system_tray/system_tray.dart';
  8. import 'utils/common.dart';
  9. // 公共布局模板
  10. import 'layouts/index.dart';
  11. // 路由管理
  12. import 'router/index.dart';
  13. void main() async {
  14.   // 初始化get_storage存储类
  15.   await GetStorage.init();
  16.   // 初始化media_kit视频套件
  17.   WidgetsFlutterBinding.ensureInitialized();
  18.   MediaKit.ensureInitialized();
  19.   initSystemTray();
  20.   runApp(const MyApp());
  21.   // 初始化bitsdojo_window窗口
  22.   doWhenWindowReady(() {
  23.     appWindow.size = const Size(850, 620);
  24.     appWindow.minSize = const Size(700, 500);
  25.     appWindow.alignment = Alignment.center;
  26.     appWindow.title = 'Flutter3-WinChat';
  27.     appWindow.show();
  28.   });
  29. }
  30. class MyApp extends StatelessWidget {
  31.   const MyApp({super.key});
  32.   @override
  33.   Widget build(BuildContext context) {
  34.     return GetMaterialApp(
  35.       title: 'FLUTTER3 WINCHAT',
  36.       debugShowCheckedModeBanner: false,
  37.       theme: ThemeData(
  38.         colorScheme: ColorScheme.fromSeed(seedColor: Color(0xFF07C160)),
  39.         useMaterial3: true,
  40.         // 修正windows端字体粗细不一致
  41.         fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null,
  42.       ),
  43.       home: const Layout(),
  44.       // 初始路由
  45.       initialRoute: Common.isLogin() ? '/index' :'/login',
  46.       // 路由页面
  47.       getPages: routes,
  48.     );
  49.   }
  50. }
  51. // 创建系统托盘图标
  52. Future<void> initSystemTray() async {
  53.   String trayIco = 'assets/images/tray.ico';
  54.   SystemTray systemTray = SystemTray();
  55.   // 初始化系统托盘
  56.   await systemTray.initSystemTray(
  57.     title: 'system-tray',
  58.     iconPath: trayIco,
  59.   );
  60.   // 右键菜单
  61.   final Menu menu = Menu();
  62.   await menu.buildFrom([
  63.     MenuItemLabel(label: '打开主界面', onClicked: (menuItem) => appWindow.show()),
  64.     MenuItemLabel(label: '隐藏窗口', onClicked: (menuItem) => appWindow.hide()),
  65.     MenuItemLabel(label: '设置中心', onClicked: (menuItem) => Get.toNamed('/setting')),
  66.     MenuItemLabel(label: '关于', onClicked: (menuItem) => {}),
  67.     MenuItemLabel(label: '退出', onClicked: (menuItem) => appWindow.close()),
  68.   ]);
  69.   await systemTray.setContextMenu(menu);
  70.   // 右键事件
  71.   systemTray.registerSystemTrayEventHandler((eventName) {
  72.     debugPrint('eventName: $eventName');
  73.     if (eventName == kSystemTrayEventClick) {
  74.       Platform.isWindows ? appWindow.show() : systemTray.popUpContextMenu();
  75.     } else if (eventName == kSystemTrayEventRightClick) {
  76.       Platform.isWindows ? systemTray.popUpContextMenu() : appWindow.show();
  77.     }
  78.   });
  79. }
复制代码
使用 bitsdojo_window 插件进行窗口管理。支持无边框窗口,窗口尺寸大小,自定义系统操作按钮(最大化/最小化/关闭)。
https://pub-web.flutter-io.cn/packages/bitsdojo_window
使用 system_tray 插件管理系统托盘图标。
34.png

https://pub-web.flutter-io.cn/packages/system_tray
flutter3公共布局

35.png

项目整体布局分为菜单栏+侧边栏+右侧主区域三个模块。
36.png
  1. class Layout extends StatefulWidget {
  2.   const Layout({
  3.     super.key,
  4.     this.activitybar = const Activitybar(),
  5.     this.sidebar,
  6.     this.child,
  7.     this.showSidebar = true,
  8.   });
  9.   final Widget? activitybar; // 左侧菜单栏
  10.   final Widget? sidebar; // 侧边栏
  11.   final Widget? child; // 右侧内容区域
  12.   final bool showSidebar; // 是否显示侧边栏
  13.   @override
  14.   State<Layout> createState() => _LayoutState();
  15. }
  16. class _LayoutState extends State<Layout> {
  17.   // 置顶窗口
  18.   bool winTopMost = false;
  19.   
  20.   @override
  21.   void initState() {
  22.     super.initState();
  23.   }
  24.   @override
  25.   void dispose() {
  26.     super.dispose();
  27.   }
  28.   @override
  29.   Widget build(BuildContext context) {
  30.     return Scaffold(
  31.       backgroundColor: Colors.grey[100],
  32.       body: Flex(
  33.         direction: Axis.horizontal,
  34.         children: [
  35.           // 左侧菜单栏
  36.           MoveWindow(
  37.             child: widget.activitybar
  38.           ),
  39.           // 侧边栏
  40.           Visibility(
  41.             visible: widget.showSidebar,
  42.             child: SizedBox(
  43.               // ...
  44.             ),
  45.           ),
  46.           // 主体容器
  47.           Expanded(
  48.             child: Column(
  49.               children: [
  50.                 // 导航栏
  51.                 WindowTitleBarBox(
  52.                   child: Row(
  53.                     children: [
  54.                       Expanded(
  55.                         child: MoveWindow(),
  56.                       ),
  57.                       // 右上角操作按钮组
  58.                       Winbtn(
  59.                         // ...
  60.                       ),
  61.                     ],
  62.                   ),
  63.                 ),
  64.                 // 内容区域
  65.                 Expanded(
  66.                   child: Container(
  67.                     child: widget.child,
  68.                   ),
  69.                 ),
  70.               ],
  71.             ),
  72.           ),
  73.         ],
  74.       ),
  75.     );
  76.   }
  77. }
复制代码
flutter3路由配置

37.png
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import '../utils/common.dart';
  4. /* 引入路由页面 */
  5. import '../views/auth/login.dart';
  6. import '../views/auth/register.dart';
  7. // 首页
  8. import '../views/index/index.dart';
  9. // 通讯录
  10. import '../views/contact/index.dart';
  11. import '../views/contact/addfriends.dart';
  12. import '../views/contact/newfriends.dart';
  13. import '../views/contact/uinfo.dart';
  14. // 收藏
  15. import '../views/favor/index.dart';
  16. import '../views/favor/write.dart';
  17. // 我的
  18. import '../views/my/index.dart';
  19. import '../views/my/setting.dart';
  20. import '../views/my/recharge.dart';
  21. import '../views/my/wallet.dart';
  22. // 朋友圈
  23. import '../views/fzone/index.dart';
  24. import '../views/fzone/publish.dart';
  25. // 短视频
  26. import '../views/fvideo/index.dart';
  27. // 聊天
  28. import '../views/chat/group-chat/chat.dart';
  29. // 路由地址集合
  30. final Map<String, Widget> routeMap = {
  31.   '/index': const Index(),
  32.   '/contact': const Contact(),
  33.   '/addfriends': const AddFriends(),
  34.   '/newfriends': const NewFriends(),
  35.   '/uinfo': const Uinfo(),
  36.   '/favor': const Favor(),
  37.   '/writefavor': const WriteFavor(),
  38.   '/my': const My(),
  39.   '/setting': const Setting(),
  40.   '/recharge': const Recharge(),
  41.   '/wallet': const Wallet(),
  42.   '/fzone': const Fzone(),
  43.   '/publish': const PublishFzone(),
  44.   '/fvideo': const Fvideo(),
  45.   '/chat': const Chat(),
  46. };
  47. final List<GetPage> patchRoute = routeMap.entries.map((e) => GetPage(
  48.   name: e.key, // 路由名称
  49.   page: () => e.value, // 路由页面
  50.   transition: Transition.noTransition, // 跳转路由动画
  51.   middlewares: [AuthMiddleware()], // 路由中间件
  52. )).toList();
  53. final List<GetPage> routes = [
  54.   GetPage(name: '/login', page: () => const Login()),
  55.   GetPage(name: '/register', page: () => const Register()),
  56.   ...patchRoute,
  57. ];
  58. // 路由拦截
  59. class AuthMiddleware extends GetMiddleware {
  60.   @override
  61.   RouteSettings? redirect(String? route) {
  62.     return Common.isLogin() ? null : const RouteSettings(name: '/login');
  63.   }
  64. }
复制代码
flutter3+bitsdojo_window自定义无边框窗口

38.png

39.png

40.png
  1. Widget build(BuildContext context){
  2.   return Row(
  3.     children: [
  4.       Container(
  5.         child: widget.leading,
  6.       ),
  7.       Visibility(
  8.         visible: widget.minimizable,
  9.         child: MouseRegion(
  10.           cursor: SystemMouseCursors.click,
  11.           child: SizedBox(
  12.             width: 32.0,
  13.             height: 36.0,
  14.             child: MinimizeWindowButton(colors: buttonColors, onPressed: handleMinimize,),
  15.           )
  16.         ),
  17.       ),
  18.       Visibility(
  19.         visible: widget.maximizable,
  20.         child: MouseRegion(
  21.           cursor: SystemMouseCursors.click,
  22.           child: SizedBox(
  23.             width: 32.0,
  24.             height: 36.0,
  25.             child: isMaximized ?
  26.             RestoreWindowButton(colors: buttonColors, onPressed: handleMaxRestore,)
  27.             :
  28.             MaximizeWindowButton(colors: buttonColors, onPressed: handleMaxRestore,),
  29.           ),
  30.         ),
  31.       ),
  32.       Visibility(
  33.         visible: widget.closable,
  34.         child: MouseRegion(
  35.           cursor: SystemMouseCursors.click,
  36.           child: SizedBox(
  37.             width: 32.0,
  38.             height: 36.0,
  39.             child: CloseWindowButton(colors: closeButtonColors, onPressed: handleExit,),
  40.           ),
  41.         ),
  42.       ),
  43.       Container(
  44.         child: widget.trailing,
  45.       ),
  46.     ],
  47.   );
  48. }
复制代码
  1. // 监听窗口尺寸变化
  2. @override
  3. void didChangeMetrics() {
  4.   super.didChangeMetrics();
  5.   WidgetsBinding.instance.addPostFrameCallback((_) {
  6.     setState(() {
  7.       isMaximized = appWindow.isMaximized;
  8.     });
  9.   });
  10. }
  11. // 最小化
  12. void handleMinimize() {
  13.   appWindow.minimize();
  14. }
  15. // 设置最大化/恢复
  16. void handleMaxRestore() {
  17.   appWindow.maximizeOrRestore();
  18. }
  19. // 关闭
  20. void handleExit() {
  21.   showDialog(
  22.     context: context,
  23.     builder: (context) {
  24.       return AlertDialog(
  25.         content: const Text('是否最小化至托盘,不退出程序?', style: TextStyle(fontSize: 16.0),),
  26.         backgroundColor: Colors.white,
  27.         shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
  28.         elevation: 3.0,
  29.         actionsPadding: const EdgeInsets.all(15.0),
  30.         actions: [
  31.           TextButton(
  32.             onPressed: () {
  33.               Get.back();
  34.               appWindow.hide();
  35.             },
  36.             child: const Text('最小化至托盘', style: TextStyle(color: Colors.blue),)
  37.           ),
  38.           TextButton(
  39.             onPressed: () {
  40.               Get.back();
  41.               appWindow.close();
  42.             },
  43.             child: const Text('退出系统', style: TextStyle(color: Colors.red),)
  44.           ),
  45.         ],
  46.       );
  47.     }
  48.   );
  49. }
复制代码
flutter3小视频模块

41.png

使用media_kit视频套件实现类似抖音短视频,支持点击暂停/播放、上下滑动切换功能。
底部mini播放进度条支持拖拽、点击播放位置功能。
  1. // mini播放进度条
  2. Positioned(
  3.   bottom: 10.0,
  4.   left: 6.0,
  5.   right: 6.0,
  6.   child: Visibility(
  7.     visible: videoIndex == index && position > Duration.zero,
  8.     child: Listener(
  9.       child: SliderTheme(
  10.         data: SliderThemeData(
  11.           trackHeight: sliderDraging ? 6.0 : 2.0,
  12.           thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4.0), // 调整滑块的大小
  13.           // trackShape: RectangularSliderTrackShape(), // 使用矩形轨道形状
  14.           overlayShape: RoundSliderOverlayShape(overlayRadius: 0), // 去掉Slider默认上下边距间隙
  15.           inactiveTrackColor: Colors.white24, // 设置非活动进度条的颜色
  16.           activeTrackColor: Colors.white, // 设置活动进度条的颜色
  17.           thumbColor: Colors.white, // 设置滑块的颜色
  18.           overlayColor: Colors.transparent, // 设置滑块覆盖层的颜色
  19.         ),
  20.         child: Slider(
  21.           value: sliderValue,
  22.           onChanged: (value) async {
  23.             // debugPrint('当前视频播放时间$value');
  24.             setState(() {
  25.               sliderValue = value;
  26.             });
  27.             // 跳转播放时间
  28.             await player.seek(duration * value.clamp(0.0, 1.0));
  29.           },
  30.           onChangeEnd: (value) async {
  31.             setState(() {
  32.               sliderDraging = false;
  33.             });
  34.             // 继续播放
  35.             if(!player.state.playing) {
  36.               await player.play();
  37.             }
  38.           },
  39.         ),
  40.       ),
  41.       onPointerMove: (e) {
  42.         setState(() {
  43.           sliderDraging = true;
  44.         });
  45.       },
  46.     ),
  47.   ),
  48. )
复制代码
flutter3聊天模板

42.png

聊天编辑框支持多行文本、超过高度出现滚动条、光标位置插入emo表情,支持链接。
43.png

优化了类似微信按住说话、左滑取消、右滑转文字功能。
44.png


综上就是flutter3实战仿微信客户端聊天系统的一些知识分享,希望对大家有所帮助!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册