找回密码
 立即注册
首页 业界区 安全 最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋 ...

最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋友圈

时思美 5 小时前
2025原创研发flutter3+dart3实战仿微信App聊天系统Flutter3Chat
flutter3_wechat:基于最新跨平台框架flutter3.32+dart3.8+get_storage+photo_view从0-1打造仿微信app聊天项目。包含聊天、通讯录、我的及朋友圈等模块。实现发送文字+emo表情消息、长按仿微信语音操作、图片/链接预览等功能。
1.png

技术栈


  • 编辑器:VScode
  • 框架技术:Flutter3.32+Dart3.8
  • 组件库:material-design3
  • 弹窗组件:showDialog/SimpleDialog/showModalBottomSheet/AlertDialog
  • 图片预览:photo_view^0.15.0
  • 存储组件:get_storage^2.1.1
  • 下拉刷新:easy_refresh^3.4.0
  • toast提示:toast^0.3.0
  • 网址预览组件:url_launcher^6.3.1
2.png

3.gif

4.gif

项目框架目录

5.png

flutter3-chat聊天app项目已经更新到我的原创作品集。

flutter3.32+dart3.8仿微信App聊天界面|朋友圈
6.gif

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

flutter3沉浸式渐变导航条

31.png

32.png

33.png

通过配置AppBar提供的可伸缩灵活区域属性 flexibleSpace 搭配gradient即可快速实现渐变导航栏。
  1. AppBar(
  2.   title: Text('Flutter3-Chat'),
  3.   flexibleSpace: Container(
  4.     decoration: const BoxDecoration(
  5.       gradient: LinearGradient(
  6.         begin: Alignment.topLeft,
  7.         end: Alignment.bottomRight,
  8.         colors: [
  9.           Color(0xFF0091EA), Color(0xFF07C160)
  10.         ],
  11.       )
  12.     ),
  13.   )
  14. ),
复制代码
flutter3仿微信PopupMenu下拉菜单/下拉刷新

34.png

flutter提供的PopupMenuButton组件实现下拉菜单功能。
  1. PopupMenuButton(
  2.   icon: FStyle.iconfont(0xe62d, size: 17.0),
  3.   offset: const Offset(0, 50.0),
  4.   tooltip: '',
  5.   color: const Color(0xFF353535),
  6.   itemBuilder: (BuildContext context) {
  7.     return <PopupMenuItem>[
  8.       popupMenuItem(0xe666, '发起群聊', 0),
  9.       popupMenuItem(0xe75c, '添加朋友', 1),
  10.       popupMenuItem(0xe603, '扫一扫', 2),
  11.       popupMenuItem(0xe6ab, '收付款', 3),
  12.     ];
  13.   },
  14.   onSelected: (value) {
  15.     switch(value) {
  16.       case 0:
  17.         print('发起群聊');
  18.         break;
  19.       case 1:
  20.         Navigator.pushNamed(context, '/addfriends');
  21.         break;
  22.       case 2:
  23.         print('扫一扫');
  24.         break;
  25.       case 3:
  26.         print('收付款');
  27.         break;
  28.     }
  29.   },
  30. )
复制代码
35.png

下拉刷新、上拉加载更多是通过 easy_refresh 组件实现功能。
  1. EasyRefresh(
  2.   // 下拉加载提示
  3.   header: const ClassicHeader(
  4.     // showMessage: false,
  5.   ),
  6.   // 加载更多提示
  7.   footer: ClassicFooter(),
  8.   // 下拉刷新逻辑
  9.   onRefresh: () async {
  10.     // ...下拉逻辑
  11.     await Future.delayed(const Duration(seconds: 2));
  12.   },
  13.   // 上拉加载逻辑
  14.   onLoad: () async {
  15.     // ...
  16.   },
  17.   child: ListView.builder(
  18.     itemCount: chatList.length,
  19.     itemBuilder: (context, index) {
  20.       return Ink(
  21.         // ...
  22.       );
  23.     },
  24.   ),
  25. )
复制代码
36.png

37.png

38.png

弹窗功能均是自定义AlertDialog实现效果。通过无限制容器UnconstrainedBox配合SizedBox组件实现自定义窗口大小。
  1. // 关于弹窗
  2. void aboutAlertDialog(BuildContext context) {
  3.   showDialog(
  4.     context: context,
  5.     builder: (context) {
  6.       return UnconstrainedBox(
  7.         constrainedAxis: Axis.vertical,
  8.         child: SizedBox(
  9.           width: 320.0,
  10.           child: AlertDialog(
  11.             contentPadding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
  12.             backgroundColor: Colors.white,
  13.             surfaceTintColor: Colors.white,
  14.             shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
  15.             content: Padding(
  16.               padding: const EdgeInsets.symmetric(horizontal: 10.0),
  17.               child: Column(
  18.                 mainAxisSize: MainAxisSize.min,
  19.                 children: [
  20.                   Image.asset('assets/images/logo.png', width: 90.0, height: 90.0, fit: BoxFit.cover,),
  21.                   const SizedBox(height: 10.0),
  22.                   const Text('Flutter3-WChat', style: TextStyle(color: Color(0xFF0091EA), fontSize: 22.0),),
  23.                   const SizedBox(height: 5.0),
  24.                   const Text('基于flutter3+dart3开发跨平台仿微信App聊天实例。', style: TextStyle(color: Colors.black45),),
  25.                   const SizedBox(height: 20.0),
  26.                   Text('©2024/01 Andy   Q: 282310962', style: TextStyle(color: Colors.grey[400], fontSize: 12.0),),
  27.                 ],
  28.               ),
  29.             ),
  30.           ),
  31.         ),
  32.       );
  33.     }
  34.   );
  35. }
  36. // 二维码名片弹窗
  37. void qrcodeAlertDialog(BuildContext context) {
  38.   showDialog(
  39.     context: context,
  40.     builder: (context) {
  41.       return UnconstrainedBox(
  42.         constrainedAxis: Axis.vertical,
  43.         child: SizedBox(
  44.           width: 320.0,
  45.           child: AlertDialog(
  46.             contentPadding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
  47.             backgroundColor: const Color(0xFF07C160),
  48.             surfaceTintColor: const Color(0xFF07C160),
  49.             shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3.0)),
  50.             content: Padding(
  51.               padding: const EdgeInsets.symmetric(horizontal: 10.0),
  52.               child: Column(
  53.                 mainAxisSize: MainAxisSize.min,
  54.                 children: [
  55.                   Image.asset('assets/images/qrcode.png', width: 250.0, fit: BoxFit.cover,),
  56.                   const SizedBox(height: 15.0),
  57.                   const Text('扫一扫,加我公众号', style: TextStyle(color: Colors.white60, fontSize: 14.0,),),
  58.                 ],
  59.               ),
  60.             ),
  61.           ),
  62.         ),
  63.       );
  64.     }
  65.   );
  66. }
  67. // 退出登录弹窗
  68. void logoutAlertDialog(BuildContext context) {
  69.   showDialog(
  70.     context: context,
  71.     builder: (context) {
  72.       return AlertDialog(
  73.         content: const Text('确定要退出登录吗?', style: TextStyle(fontSize: 16.0),),
  74.         backgroundColor: Colors.white,
  75.         surfaceTintColor: Colors.white,
  76.         shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
  77.         elevation: 2.0,
  78.         actionsPadding: const EdgeInsets.all(15.0),
  79.         actions: [
  80.           TextButton(
  81.             onPressed: () {Navigator.of(context).pop();},
  82.             child: const Text('取消', style: TextStyle(color: Colors.black54),)
  83.           ),
  84.           TextButton(
  85.             onPressed: handleLogout,
  86.             child: const Text('退出登录', style: TextStyle(color: Colors.red),)
  87.           ),
  88.         ],
  89.       );
  90.     }
  91.   );
  92. }
复制代码
flutter3实现微信朋友圈

39.png

40.png
  1. ImageGroup(images: item['images'])
  2. ImageGroup(
  3.   images: uploadList,
  4.   album: true,
  5.   onChoose: () async {
  6.     Toast.show('选择手机相册图片', duration: 2, gravity: 1);
  7.   },
  8. )
复制代码
41.png
  1. /// 微信朋友圈九宫格图片
  2. library;
  3. import 'package:flutter/material.dart';
  4. import '../router/fade_route.dart';
  5. import 'image_viewer.dart';
  6. import '../utils/index.dart';
  7. class ImageGroup extends StatelessWidget {
  8.   const ImageGroup({
  9.     super.key,
  10.     this.images,
  11.     this.width = 200.0,
  12.     this.album = false,
  13.     this.limit = 9,
  14.     this.onChoose,
  15.   });
  16.   final List<String>? images; // 图片组
  17.   final double width; // 图片宽度
  18.   final bool album; // 是否相册/专辑(最后面显示+可选择图片)
  19.   final int limit; // 限制多少张
  20.   final Function? onChoose; // 选择图片回调
  21.   int? get count => images?.length;
  22.   List<String>? get imgList => count! >= limit ? images?.sublist(0, limit) : images;
  23.   // 创建可点击预览图片
  24.   createImage(BuildContext context, String img, int key) {
  25.     return GestureDetector(
  26.       child: Hero(
  27.         tag: 'image_${key}_$img', // 放大缩小动画效果标识
  28.         child: img == '+' ?
  29.         Container(color: Colors.transparent, child: const Icon(Icons.add, size: 30.0, color: Colors.black45),)
  30.         :
  31.         Utils.isUrl(img) ?
  32.         Image.network(
  33.           img,
  34.           width: width,
  35.           fit: BoxFit.contain,
  36.         )
  37.         :
  38.         Image.asset(
  39.           img,
  40.           width: width,
  41.           fit: BoxFit.contain,
  42.         ),
  43.       ),
  44.       onTap: () {
  45.         // 选择图片
  46.         if(img == '+') {
  47.           onChoose!();
  48.         }else {
  49.           Navigator.of(context).push(FadeRoute(route: ImageViewer(
  50.             images: album ? imgList!.sublist(0, imgList!.length - 1) : imgList,
  51.             index: key,
  52.             heroTags: imgList!.asMap().entries.map((e) => 'image_${e.key}_${e.value}').toList(),
  53.           )));
  54.         }
  55.       },
  56.     );
  57.   }
  58.   @override
  59.   Widget build(BuildContext context){
  60.     // 一张图片
  61.     if(count == 1 && !album) {
  62.       return SizedBox(
  63.         width: width,
  64.         child: createImage(context, imgList![0], 0),
  65.       );
  66.     }
  67.     if(album && count! < limit) {
  68.       imgList?.add('+');
  69.     }
  70.    
  71.     // 多张图片
  72.     return GridView(
  73.       shrinkWrap: true,
  74.       physics: const NeverScrollableScrollPhysics(),
  75.       gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
  76.         // 横轴元素个数
  77.         crossAxisCount: 3,
  78.         // 纵轴间距
  79.         mainAxisSpacing: 5.0,
  80.         // 横轴间距
  81.         crossAxisSpacing: 5.0,
  82.         // 子组件宽高比例
  83.         childAspectRatio: 1,
  84.       ),
  85.       children: imgList!.asMap().entries.map((e) {
  86.         return Container(
  87.           color: Colors.grey[100],
  88.           child: createImage(context, e.value, e.key),
  89.         );
  90.       }).toList(),
  91.     );
  92.   }
  93. }
复制代码
flutter3聊天功能

42.png

文本框TextField设置maxLines: null即可实现多行文本输入,支持图文emoj混排,网址连接识别等功能。
  1. // 输入框
  2. Offstage(
  3.   offstage: voiceBtnEnable,
  4.   child: ConstrainedBox(
  5.     constraints: BoxConstraints(maxHeight: 300.0),
  6.     child: TextField(
  7.       decoration: InputDecoration(
  8.         isDense: true,
  9.         hoverColor: Colors.transparent,
  10.         border: OutlineInputBorder(borderSide: BorderSide.none),
  11.         contentPadding: EdgeInsets.fromLTRB(10, 0, 10, 0)
  12.       ),
  13.       style: const TextStyle(fontSize: 16.0,),
  14.       maxLines: null,
  15.       controller: editorController,
  16.       focusNode: editorFocusNode,
  17.       cursorColor: const Color(0xFF07C160),
  18.       onChanged: (value) {},
  19.     ),
  20.   ),
  21. )
复制代码
43.png

44.gif
  1. // 语音
  2. Offstage(
  3.   offstage: !voiceBtnEnable,
  4.   child: GestureDetector(
  5.     child: Container(
  6.       decoration: BoxDecoration(
  7.         color: Colors.white,
  8.         borderRadius: BorderRadius.circular(5),
  9.       ),
  10.       alignment: Alignment.center,
  11.       height: 40.0,
  12.       width: double.infinity,
  13.       child: Text(voiceTypeMap[voiceType], style: const TextStyle(fontSize: 15.0),),
  14.     ),
  15.     onPanStart: (details) {
  16.       setState(() {
  17.         voiceType = 1;
  18.         voicePanelEnable = true;
  19.       });
  20.     },
  21.     onPanUpdate: (details) {
  22.       Offset pos = details.globalPosition;
  23.       double swipeY = MediaQuery.of(context).size.height - 120;
  24.       double swipeX = MediaQuery.of(context).size.width / 2 + 50;
  25.       setState(() {
  26.         if(pos.dy >= swipeY) {
  27.           voiceType = 1; // 松开发送
  28.         }else if (pos.dy < swipeY && pos.dx < swipeX) {
  29.           voiceType = 2; // 左滑松开取消
  30.         }else if (pos.dy < swipeY && pos.dx >= swipeX) {
  31.           voiceType = 3; // 右滑语音转文字
  32.         }
  33.       });
  34.     },
  35.     onPanEnd: (details) {
  36.       // print('停止录音');
  37.       setState(() {
  38.         switch(voiceType) {
  39.           case 1:
  40.             Toast.show('发送录音文件', duration: 1, gravity: 1);
  41.             voicePanelEnable = false;
  42.             break;
  43.           case 2:
  44.             Toast.show('取消发送', duration: 1, gravity: 1);
  45.             voicePanelEnable = false;
  46.             break;
  47.           case 3:
  48.             Toast.show('语音转文字', duration: 1, gravity: 1);
  49.             voicePanelEnable = true;
  50.             voiceToTransfer = true;
  51.             break;
  52.         }
  53.         voiceType = 0;
  54.       });
  55.     },
  56.   ),
  57. )
复制代码
flutter3绘制聊天箭头
45.png
  1. // 绘制聊天箭头
  2. class ArrowShape extends CustomPainter {
  3.   ArrowShape({
  4.     required this.arrowColor,
  5.     this.arrowSize = 7,
  6.   });
  7.   final Color arrowColor; // 箭头颜色
  8.   final double arrowSize; // 箭头大小
  9.   @override
  10.   void paint(Canvas canvas, Size size) {
  11.     var paint = Paint()..color = arrowColor;
  12.     var path = Path();
  13.     path.lineTo(-arrowSize, 0);
  14.     path.lineTo(0, arrowSize);
  15.     path.lineTo(arrowSize, 0);
  16.     canvas.drawPath(path, paint);
  17.   }
  18.   @override
  19.   bool shouldRepaint(CustomPainter oldDelegate) {
  20.     return false;
  21.   }
  22. }
复制代码
综上就是Flutter3+Dart3实战仿微信App聊天项目的一些知识分享,感谢大家的阅读与支持!
附上几个最新项目实例
最新版uniapp+vue3+uv-ui跨三端短视频+直播+聊天【H5+小程序+App端】
Uniapp-DeepSeek跨三端AI助手|uniapp+vue3+deepseek-v3流式ai聊天模板

Electron35-DeepSeek桌面端AI系统|vue3.5+electron+arco客户端ai模板
vue3-webseek网页版AI问答|Vite6+DeepSeek+Arco流式ai聊天打字效果
flutter3-dymall仿抖音直播商城|Flutter3.27短视频+直播+聊天App实例
tauri2.0-admin桌面端后台系统|Tauri2+Vite5+ElementPlus管理后台EXE程序
Tauri2.0+Vite5聊天室|vue3+tauri2+element-plus仿微信|tauri聊天应用
Electron32-ViteOS桌面版os系统|vue3+electron+arco客户端OS管理模板
uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
46.gif

 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册