欢迎关注微信公众号:FSA全栈行动 👋
一、概述
距离以上两篇文章的发布已经快 1 年了, 当时的最新版本是 0.2.0
,现在,chat_bottom_container
迎来了 0.4.0
版本。
这次的更新主要是带来了自定义底部容器的功能,即容器的结构可完全由外部去定义,那可以通过这个功能去做什么呢?
- 保持面板视图的状态
- 实现任意动画(这次谁再说动画生硬,那就是你自己的问题了 😒)
二、效果
按照惯例,这里先附上效果图,好让大家直观感受一下~
例子 | 效果图 |
---|---|
Fade | ![]() |
Cube | ![]() |
Concentric | ![]() |
Rotation | ![]() |
ZoomIn | ![]() |
好了,更多效果大家可以跑示例去看看,下面我们一起来看看怎么使用吧。
三、集成
将 chat_bottom_container
添加到你的 pubspec.yaml
文件中
yaml
dependencies:
chat_bottom_container: ^0.4.0
最新版本可到 pub.dev
上复制粘贴 pub.dev/packages/ch...
Android
端需要添加 jitpack
仓库到你的项目根目录下的 build.gradle
文件中:
gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
注:无论是
iOS
还是Android
,在下载依赖时都需要使用魔法❗️❗️❗️ 特别是iOS
,下载失败了,请先考虑是自己的节点问题,而不是别人的问题 🫵
四、使用
页面结构如下
dart
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: _buildAppBar(),
body: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 列表
Expanded(child: ChatAnimationListView()),
// 功能条(输入框、表情按钮、工具按钮等)
ChatAnimationPanelBar(),
// 底部容器
ChatAnimationPanelContainer(),
],
),
);
这里主要看底部容器 ChatAnimationPanelContainer
对应的面板类型枚举
dart
enum ChatAnimationPanelType {
none,
keyboard,
emoji,
tool,
}
底部容器的实现
dart
ChatBottomPanelContainer<ChatAnimationPanelType>(
// 控制器(必传,ChatBottomPanelContainerController)
controller: state.controller,
// 输入框焦点对象(必传,FocusNode)
inputFocusNode: state.inputFocusNode,
// 面板类型切换回调(按需实现,主要用来记录当前的面板类型是什么)
onPanelTypeChange: logic.onPanelTypeChange,
// 自定义容器回调
customPanelContainer: (panelType, data) {
if (!mounted) return const SizedBox.shrink();
Widget? container = state.customPanelContainer;
if (container != null) {
// 已创建,刷新自定义容器,可以按需只刷新自定义容器里的子部件
logic.update([
ChatAnimationUpdateType.customPanelContainer,
]);
return container;
}
// 未创建,则创建
container = const ChatAnimationFadePanelContainer();
// 记录起来
state.customPanelContainer = container;
return container;
},
);
这里以上述效果图中的 Fade
为例,即 ChatAnimationFadePanelContainer
,主要是通过 animated_size_and_fade
这个第三方库去实现切换动画。
dart
// ChatAnimationFadePanelContainer
@override
Widget build(BuildContext context) {
return GetBuilder<ChatAnimationLogic>(
tag: logicTag,
id: ChatAnimationUpdateType.customPanelContainer,
builder: (_) {
if (!mounted) return const SizedBox.shrink();
// 构建对应类型的视图
// 如:常规安全区、键盘占位视图、表情面板、功能面板等
Widget resultWidget = logic.buildPanelWidget(
state.currentPanelType,
useKeyboardHeight: false,
);
// 包裹 AnimatedSizeAndFade 实现切换动画
resultWidget = AnimatedSizeAndFade(
fadeDuration: const Duration(milliseconds: 500),
sizeDuration: const Duration(milliseconds: 300),
child: resultWidget,
);
return resultWidget;
},
);
}
至此,通过 customPanelContainer
实现自定义容器的大体用法已经展示完毕了~
不过,相信聪明的你肯定会问,难道要完全自定义?能不能保留部分视图由 chat_bottom_container
帮我实现呢?比如常规安全区、键盘占位视图。
当然可以,接下来讲讲几点细节。
五、细节
构建内置面板
dart
enum ChatBottomPanelType {
// 常规安全区
none,
// 键盘占位视图
keyboard,
// 其它面板(Emoji、Tool)
other,
}
Widget? buildInPanel(ChatBottomPanelType panelType) {
switch (panelType) {
case ChatBottomPanelType.none:
return _state?.buildSafeArea.call();
case ChatBottomPanelType.keyboard:
return _state?.buildKeyboardPlaceholderPanel.call();
case ChatBottomPanelType.other:
return _state?.buildOtherPanel.call();
}
}
通过调用 ChatBottomPanelContainerController
的 buildInPanel
方法,并传入 .none
或 .keyboard
时即可获取到相应的内置面板视图,而 .other
是获取外部 otherPanelWidget
回调返回的视图,未实现则得到 null
。
以下是构建对应类型的视图的示例代码
dart
Widget buildPanelWidget(
ChatAnimationPanelType type,
...
) {
final panelController = state.controller;
...
Widget resultWidget;
switch (type) {
case ChatAnimationPanelType.none:
// 常规安全区
resultWidget = panelController.buildInPanel(ChatBottomPanelType.none) ??
const SizedBox();
...
break;
case ChatAnimationPanelType.keyboard:
// 键盘占位视图
resultWidget = panelController.buildInPanel(ChatBottomPanelType.keyboard) ??
const SizedBox.shrink();
...
break;
case ChatAnimationPanelType.emoji:
// 表情面板
resultWidget = ChatAnimationEmojiPanel(
...
);
break;
case ChatAnimationPanelType.tool:
// 工具面板
resultWidget = ChatAnimationToolPanel(
...
);
break;
}
...
// 设置 key,这对 AnimatedSwitcher 来说很重要
resultWidget = SizedBox(
key: ValueKey('$type'),
width: double.infinity,
child: resultWidget,
);
return resultWidget;
}
AnimatedSwitcher
动画
如果你使用 AnimatedSwitcher
来实现面板切换动画,那么建议你与上述代码一样,给每个面板都设置一个 key
(通常使用 ValueKey
),这是为了避免在切换面板时,AnimatedSwitcher
认为前后面板是同一个而导致动画失效。
面板视图保持状态
其实是否能保持面板的状态取决于你的布局实现,比如可以使用 IndexedStack
,如果想要在保持状态的同时还有动画,就去找相应的动画库即可,比如示例中使用的 transitioned_indexed_stack
。
六、最后
好了,上述便是该库的更新内容,如果你有其它好用的动画库,可以留言跟大家分享 🫶
这里惯例附上 GitHub
地址: github.com/LinXunFeng/... ,如果接入上有什么问题,可以在链接中查看 demo
演示代码。
开源不易,如果你也觉得这个库好用,请不吝给个 Star
👍 ,并多多支持!
本篇到此结束,感谢大家的支持,我们下次再见! 👋
如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有
iOS
技术,还有Android
,Flutter
,Python
等文章, 可能有你想要了解的技能知识点哦~