
总结
- 花时间重构了之前写的聊天程序的页面。
- 使用最新的Flutter Sdk 重写。
- 优化了高斯模糊的写法。
- 优化了对安全区域的判断逻辑。
- 增加文字和图片的发送效果。
- 增加图片查看功能。
项目中使用到的一些第三方组件
yaml
get: ^4.7.3
# 系统接口
device_info_plus: ^12.2.0 # 设备信息(全平台支持)
permission_handler: ^12.0.1 # 权限处理(不支持PC - MacOS)
# 图像渲染
flutter_svg: ^2.2.3
extended_image: ^10.0.1 # 图片展示
# 数据存储
xml: ^6.6.1 # xml解析 - 解析表情包文件
shared_preferences: ^2.5.4
# UI交互
easy_refresh: ^3.4.0 # 下拉刷新
flutter_slidable: ^4.0.3 # 滑动删除
flutter_smart_dialog: ^4.9.8+9 # 消息弹窗
flutter_keyboard_visibility: ^6.0.0 # 键盘状态监听
chat_bottom_container: ^0.4.0 # 输入框切换动画组件
# 本地资源选择
wechat_assets_picker: ^10.0.0 # 图片\视频选择器(不支持PC)
wechat_camera_picker: ^4.4.0 # 图片\视频拍摄器(不支持PC)
关于IOS上的一些权限配置
Podfile 文件
js
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_CAMERA=1',
'PERMISSION_PHOTOS=1',
'PERMISSION_MICROPHONE=1',
]
end
end
end
Info.plist 中增加对权限的描述
xml
<key>NSCameraUsageDescription</key>
<string>xxx</string>
<key>NSAppleMusicUsageDescription</key>
<string>xxx</string>
<key>NSMicrophoneUsageDescription</key>
<string>xxx</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>xxx</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>xxx</string>
自定义滚动透明化的Appbar标题

dart
/// 滚动动画的App标题
mixin AppBarMixin on GetxController {
/// 控制Appbar标题透明度的控制器
AnimationController? fadeController;
/// 透明度动画参数
late Animation<double> fadeAnimation;
/// 滚动列表的控制器
final ScrollController scrollController = ScrollController();
/// 初始化
void onInitAnimation(GetSingleTickerProviderStateMixin item) {
fadeController = AnimationController(
duration: Duration(milliseconds: 300),
vsync: item,
);
fadeAnimation = Tween<double>(begin: 0, end: 1).animate(fadeController!);
scrollController.addListener(() {
if (scrollController.offset >= 50) {
//titleOpacity.value = 1;
fadeController?.forward();
} else {
if (fadeAnimation.value != 0 && scrollController.offset > 0) {
var fade = scrollController.offset / 50;
fadeController?.animateTo(fade);
} else {
//titleOpacity.value = 0;
fadeController?.reverse();
}
}
});
}
@override
void onClose() {
fadeController?.dispose();
scrollController.dispose();
super.onClose();
}
}
Hero动画
动画的Key需要传递到第二个页面。

dart
Get.to(
() => PreviewImagePage(),
transition: Transition.noTransition,
arguments: {
"hero": message.heroKey,
"source": imageMessage.image,
},
);
/// Hero 动画 Key
String heroKey = Get.arguments['hero'];
Hero(
tag: heroKey,
child: widget,
),
输入框切换动画

dart
使用的第三方组件
chat_bottom_container: ^0.4.0 # 输入框切换动画组件
消息定义
dart
import 'dart:math';
/// 消息基类
abstract class Message {
final String name;
final String avatar;
final bool self;
final String id = Random().nextInt(100000000).toString();
/// 正在发送
final bool sending = false;
/// 发送失败
final bool failed = false;
/// 是否群聊
final bool isGroup = false;
abstract final bool center;
abstract final bool canClick;
abstract final MessageKind kind;
Message({
required this.avatar,
required this.name,
required this.self,
});
}
enum MessageKind {
unkonw,
text,
image,
video,
}
/// 文本消息
class TextMessage extends Message {
final String text;
TextMessage({
required this.text,
required super.avatar,
required super.name,
required super.self,
});
@override
bool get center => false;
@override
bool get canClick => false;
@override
MessageKind get kind => MessageKind.text;
}
/// 图片消息
class ImageMessage extends Message {
final String image;
final double w;
final double h;
ImageMessage({
required this.image,
required super.avatar,
required super.name,
required super.self,
required this.w,
required this.h,
});
/// 跳转的页动画Key
String get heroKey => "PreviewImage-$id";
@override
bool get center => false;
@override
bool get canClick => true;
@override
MessageKind get kind => MessageKind.image;
}
- 最后附上源码
- 帮我点赞哦👍 😀
- 源码地址