Flutter3WinChat客户端聊天|flutter3.x+getx桌面端仿微信EXE实例。
该项目前后花了差不多大半个月时间,旨在通过这个项目探索Flutter桌面端开发。
技术框架
- 编辑器:vscode
- 窗口管理:bitsdojo_window: ^0.1.6
- 托盘图标:system_tray: ^2.0.3
- 路由/状态管理:get: ^4.6.6
- 本地存储:get_storage: ^2.1.1
- 图片预览插件:photo_view: ^0.14.0
- 网址预览:url_launcher: ^6.2.4
- 视频组件:media_kit: ^1.1.10+1
- 文件选择器:file_picker: ^6.1.1
整个项目使用到了上面的一些技术,窗口管理采用的bitsdojo_window
插件,不过window_manager
这个窗口管理插件也不错,不过相对重量级一些。
https://pub-web.flutter-io.cn/packages/bitsdojo_window
https://pub-web.flutter-io.cn/packages/window_manager
项目结构
使用flutter create flutter_app
创建一个新项目。
使用flutter run -d windows
来运行到window桌面。
Flutter路由/状态管理
使用Getx来作为路由及状态管理。
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'FLUTTER3 WINCHAT',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: FStyle.primaryColor,
useMaterial3: true,
),
home: const Layout(),
// 初始路由
initialRoute: Utils.isLogin() ? '/index' :'/login',
// 路由页面
getPages: routes,
);
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// 引入工具类
import '../utils/index.dart';
/* 引入路由页面 */
import '../views/auth/login.dart';
import '../views/auth/register.dart';
// 首页
import '../views/index/index.dart';
// 通讯录
import '../views/contact/index.dart';
import '../views/contact/addfriends.dart';
import '../views/contact/newfriends.dart';
import '../views/contact/uinfo.dart';
// 收藏
import '../views/favor/index.dart';
// 我的
import '../views/my/index.dart';
import '../views/my/setting.dart';
import '../views/my/recharge.dart';
import '../views/my/wallet.dart';
// 朋友圈
import '../views/fzone/index.dart';
import '../views/fzone/publish.dart';
// 短视频
import '../views/fvideo/index.dart';
// 聊天
import '../views/chat/group-chat/chat.dart';
// 路由地址集合
final Map<String, Widget> routeMap = {
'/index': const Index(),
'/contact': const Contact(),
'/addfriends': const AddFriends(),
'/newfriends': const NewFriends(),
'/uinfo': const Uinfo(),
'/favor': const Favor(),
'/my': const My(),
'/setting': const Setting(),
'/recharge': const Recharge(),
'/wallet': const Wallet(),
'/fzone': const Fzone(),
'/publish': const PublishFzone(),
'/fvideo': const Fvideo(),
'/chat': const Chat(),
};
final List<GetPage> patchRoute = routeMap.entries.map((e) => GetPage(
name: e.key, // 路由名称
page: () => e.value, // 路由页面
transition: Transition.noTransition, // 跳转路由动画
middlewares: [AuthMiddleware()], // 路由中间件
)).toList();
final List<GetPage> routes = [
GetPage(name: '/login', page: () => const Login()),
GetPage(name: '/register', page: () => const Register()),
...patchRoute,
];
Flutter布局模板
class Layout extends StatefulWidget {
const Layout({
super.key,
this.activitybar = const Activitybar(),
this.sidebar,
this.workbench,
this.showSidebar = true,
});
final Widget? activitybar; // 左侧操作栏
final Widget? sidebar; // 侧边栏
final Widget? workbench; // 右侧工作面板
final bool showSidebar; // 是否显示侧边栏
@override
State<Layout> createState() => _LayoutState();
}
return Scaffold(
backgroundColor: Colors.grey[100],
body: Flex(
direction: Axis.horizontal,
children: [
// 左侧操作栏
MoveWindow(
child: widget.activitybar,
onDoubleTap: () => {},
),
// 侧边栏
Visibility(
visible: widget.showSidebar,
child: SizedBox(
width: 270.0,
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFEEEBE7), Color(0xFFEEEEEE)
]
),
),
child: widget.sidebar,
),
),
),
// 主体容器
Expanded(
child: Column(
children: [
WindowTitleBarBox(
child: Row(
children: [
Expanded(
child: MoveWindow(),
),
// 右上角操作按钮组
Winbtn(
leading: Row(
children: [
IconButton(onPressed: () {}, icon: const Icon(Icons.auto_fix_high), iconSize: 14.0,),
IconButton(
onPressed: () {
setState(() {
winTopMost = !winTopMost;
});
},
tooltip: winTopMost ? '取消置顶' : '置顶',
icon: const Icon(Icons.push_pin_outlined),
iconSize: 14.0,
highlightColor: Colors.transparent, // 点击水波纹颜色
isSelected: winTopMost ? true : false, // 是否选中
style: ButtonStyle(
visualDensity: VisualDensity.compact,
backgroundColor: MaterialStateProperty.all(winTopMost ? Colors.grey[300] : Colors.transparent),
shape: MaterialStatePropertyAll(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(0.0))
),
),
),
],
),
),
],
),
),
// 右侧工作面板
Expanded(
child: Container(
child: widget.workbench,
),
),
],
),
),
],
),
);
Flutter朋友圈
@override
Widget build(BuildContext context) {
return Layout(
showSidebar: false,
workbench: CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: const Color(0xFF224E7F),
foregroundColor: Colors.white,
pinned: true,
elevation: 0.0,
expandedHeight: 200.0,
leading: IconButton(icon: const Icon(Icons.arrow_back,), onPressed: () {Navigator.pop(context);}),
flexibleSpace: FlexibleSpaceBar(
title: Row(
children: <Widget>[
ClipOval(child: Image.asset('assets/images/avatar/uimg1.jpg',height: 36.0,width: 36.0,fit: BoxFit.fill)),
const SizedBox(width: 10.0),
const Text('Andy', style: TextStyle(fontSize: 14.0)),
],
),
titlePadding: const EdgeInsets.fromLTRB(55, 10, 10, 10),
background: InkWell(
child: Image.asset('assets/images/cover.jpg', fit: BoxFit.cover),
onTap: () {changePhotoAlbum(context);},
),
),
actions: <Widget>[
IconButton(icon: const Icon(Icons.favorite_border, size: 18,), onPressed: () {}),
IconButton(icon: const Icon(Icons.share, size: 18,), onPressed: () {}),
IconButton(icon: const Icon(Icons.add_a_photo, size: 18,), onPressed: () {Get.toNamed('/publish');}),
const SizedBox(width: 10.0,),
],
),
SliverToBoxAdapter(
child: UnconstrainedBox(
child: Container(
width: MediaQuery.of(context).size.height * 3 / 4,
decoration: const BoxDecoration(
color: Colors.white,
),
child: Column(
children: uzoneList.map((item) {
return Container(
padding: const EdgeInsets.all(15.0),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xFFEEEEEE), width: .5)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset(item['avatar'],height: 35.0,width: 35.0,fit: BoxFit.cover),
const SizedBox(width: 10.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(item['author'], style: TextStyle(color: Colors.indigo[400])),
const SizedBox(height: 2.0),
Text(item['content'], style: const TextStyle(color: Colors.black87, fontSize: 15.0)),
const SizedBox(height: 10.0),
GroupZone(images: item['images']),
const SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(child: Text(item['time'], style: const TextStyle(color: Colors.grey, fontSize: 12.0)),),
FStyle.iconfont(0xe653, color: Colors.black54, size: 16.0,),
],
)
],
),
),
],
),
);
}).toList(),
),
),
),
),
],
),
);
}
OK,综上就是flutter3+getx开发桌面端聊天项目的一些分享。
作者:xiaoyan2015
链接:https://juejin.cn/post/7341533476674207755
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
0条评论