flutter3-wchat:基于flutter3.x/dart3+material-ui聊天|flutter3仿微信
全新研发flutter3+dart3跨多平台仿微信App界面聊天Flutter3-Chat。
使用技术
- 框架技术:Flutter3.16.5+Dart3.2.3
- UI组件库:material-design3
- 弹窗组件:showDialog/SimpleDialog/showModalBottomSheet/AlertDialog
- 图片预览:photo_view^0.14.0
- 本地缓存:shared_preferences^2.2.2
- 下拉刷新:easy_refresh^3.3.4
- toast提示:toast^0.3.0
- 网址预览组件:url_launcher^6.2.4
项目结构框架
项目搭建
前期大家可以编译到windows调试,后期再release到手机。
运行到windows默认窗口大小为1280x720,可以修改windows/runner/main.cpp文件里面的窗口尺寸。
选择模拟器调试。目前市面上有很多类型模拟器,他们使用adb连接时都会有不同的默认端口,下面列出了一些常用的模拟器及端口号。通过adb connect连接上指定模拟器之后,执行flutter run命令即可运行项目到模拟器上面。
使用flutter create project
命令快速创建一个flutter应用。
flutter实现如上图圆角文本框及渐变按钮。
Container(
height: 40.0,
margin: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 30.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xffdddddd)),
borderRadius: BorderRadius.circular(15.0),
),
child: Row(
children: [
Expanded(
child: TextField(
keyboardType: TextInputType.phone,
controller: fieldController,
decoration: InputDecoration(
hintText: '输入手机号',
suffixIcon: Visibility(
visible: authObj['tel'].isNotEmpty,
child: InkWell(
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
onTap: handleClear,
child: const Icon(Icons.clear, size: 16.0,),
)
),
contentPadding: const EdgeInsets.symmetric(vertical: 0, horizontal: 12.0),
border: const OutlineInputBorder(borderSide: BorderSide.none),
),
onChanged: (value) {
setState(() {
authObj['tel'] = value;
});
},
),
)
],
),
),
使用Container提供的gradient实现渐变。
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 30.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
// 自定义按钮渐变色
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF0091EA), Color(0xFF07C160)
],
)
),
child: SizedBox(
width: double.infinity,
height: 45.0,
child: FilledButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.transparent),
shadowColor: MaterialStateProperty.all(Colors.transparent),
shape: MaterialStatePropertyAll(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0))
)
),
onPressed: handleSubmit,
child: const Text('登录', style: TextStyle(fontSize: 18.0),),
),
)
),
flutter实现渐变导航条
配置AppBar提供的可伸缩灵活区域属性 flexibleSpace
配合gradient即可快速实现渐变导航栏。
AppBar(
title: Text('Flutter3-Chat'),
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF0091EA), Color(0xFF07C160)
],
)
),
)
),
flutter自定义iconfont字体及badge
flutter提供了非常丰富的字体图标,通过图标组件 Icon(Icons.add)
引入即可使用。
api.flutter-io.cn/flutter/material...
另外还支持通过自定义IconData
方式自定义图标,如使用阿里iconfont图表库图标。
Icon(IconData(0xe666, fontFamily: 'iconfont'), size: 18.0)
把下载的字体文件放到assets目录
在pubspec.yaml中引入字体
class FStyle {
// 自定义iconfont图标
static iconfont(int codePoint, {double size = 16.0, Color? color}) {
return Icon(
IconData(codePoint, fontFamily: 'iconfont', matchTextDirection: true),
size: size,
color: color,
);
}
// 自定义Badge红点
static badge(int count, {
Color color = Colors.redAccent,
bool isdot = false,
double height = 18.0,
double width = 18.0
}) {
final num = count > 99 ? '99+' : count;
return Container(
alignment: Alignment.center,
height: isdot ? height / 2 : height,
width: isdot ? width / 2 : width,
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(100.00)),
child: isdot ? null : Text('$num', style: const TextStyle(color: Colors.white, fontSize: 12.0)),
);
}
}
下拉刷新、上拉加载更多是通过 easy_refresh
组件实现功能。
EasyRefresh(
// 下拉加载提示
header: const ClassicHeader(
// showMessage: false,
),
// 加载更多提示
footer: ClassicFooter(),
// 下拉刷新逻辑
onRefresh: () async {
// ...下拉逻辑
await Future.delayed(const Duration(seconds: 2));
},
// 上拉加载逻辑
onLoad: () async {
// ...
},
child: ListView.builder(
itemCount: chatList.length,
itemBuilder: (context, index) {
return Ink(
// ...
);
},
),
)
GroupZone(images: item['images']),
GroupZone(
images: uploadList,
album: true,
onChoose: () async {
Toast.show('选择手机相册图片', duration: 2, gravity: 1);
},
),
通过photo_view
实现九宫格预览大图功能。
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:photo_view/photo_view_gallery.dart';
class ImageViewer extends StatefulWidget {
const ImageViewer({
super.key,
this.images,
this.index = 0,
});
final List? images; // 预览图列表
final int index; // 当前预览图索引
@override
State<ImageViewer> createState() => _ImageViewerState();
}
class _ImageViewerState extends State<ImageViewer> {
int currentIndex = 0;
@override
void initState() {
super.initState();
currentIndex = widget.index;
}
@override
Widget build(BuildContext context) {
var imgCount = widget.images?.length;
return Scaffold(
body: Stack(
children: [
Positioned(
top: 0,
left: 0,
bottom: 0,
right: 0,
child: GestureDetector(
child: imgCount == 1 ? PhotoView(
imageProvider: AssetImage(widget.images![0]),
backgroundDecoration: const BoxDecoration(
color: Colors.black,
),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
heroAttributes: PhotoViewHeroAttributes(tag: widget.images![0]),
enableRotation: true,
)
:
PhotoViewGallery.builder(
itemCount: widget.images?.length,
builder: (context, index) {
return PhotoViewGalleryPageOptions(
imageProvider: AssetImage(widget.images![index]),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
heroAttributes: PhotoViewHeroAttributes(tag: widget.images![index]),
);
},
scrollPhysics: const BouncingScrollPhysics(),
backgroundDecoration: const BoxDecoration(
color: Colors.black,
),
pageController: PageController(initialPage: widget.index),
enableRotation: true,
onPageChanged: (index) {
setState(() {
currentIndex = index;
});
},
),
onTap: () {
Navigator.of(context).pop();
},
),
),
// 图片索引index
Positioned(
top: MediaQuery.of(context).padding.top + 15,
width: MediaQuery.of(context).size.width,
child: Center(
child: Visibility(
visible: imgCount! > 1 ? true : false,
child: Text('${currentIndex+1} / ${widget.images?.length}', style: const TextStyle(color: Colors.white)),
)
),
),
],
),
);
}
}
flutter语音聊天模块
// 语音
Offstage(
offstage: !voiceBtnEnable,
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
alignment: Alignment.center,
height: 40.0,
width: double.infinity,
child: Text(voiceTypeMap[voiceType], style: const TextStyle(fontSize: 15.0),),
),
onPanStart: (details) {
setState(() {
voiceType = 1;
voicePanelEnable = true;
});
},
onPanUpdate: (details) {
Offset pos = details.globalPosition;
double swipeY = MediaQuery.of(context).size.height - 120;
double swipeX = MediaQuery.of(context).size.width / 2 + 50;
setState(() {
if(pos.dy >= swipeY) {
voiceType = 1; // 松开发送
}else if (pos.dy < swipeY && pos.dx < swipeX) {
voiceType = 2; // 左滑松开取消
}else if (pos.dy < swipeY && pos.dx >= swipeX) {
voiceType = 3; // 右滑语音转文字
}
});
},
onPanEnd: (details) {
// print('停止录音');
setState(() {
switch(voiceType) {
case 1:
Toast.show('发送录音文件', duration: 1, gravity: 1);
voicePanelEnable = false;
break;
case 2:
Toast.show('取消发送', duration: 1, gravity: 1);
voicePanelEnable = false;
break;
case 3:
Toast.show('语音转文字', duration: 1, gravity: 1);
voicePanelEnable = true;
voiceToTransfer = true;
break;
}
voiceType = 0;
});
},
),
),
综上基本就是flutter3.x+dart3实现微信app聊天的一些知识分享。
博客:uniapp-welive:基于uni-app+vue3+pinia多端直播商城实例|uniapp仿抖...
博客:Electron-React-MacOs基于electron27+react18客户端os系统
本作品采用《CC 协议》,转载必须注明作者和本文链接