FSA全栈行动 FSA全栈行动
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr

公众号:FSA全栈行动

记录学习过程中的知识
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr
  • AndroidUI

  • Android第三方SDK

  • Android混淆

  • Android仓库

  • Android新闻

  • Android系统开发

  • Android源码

  • Android注解AOP

  • Android脚本

  • AndroidTv开发

  • AndroidNDK

  • Android音视频

  • Android热修复

  • Android性能优化

  • Android云游戏

  • Android插件化

  • iOSUI

  • iOS工具

  • iOS底层原理与应用

  • iOS组件化

  • iOS音视频

  • iOS疑难杂症

  • iOS之Swift

  • iOS之RxSwift

  • iOS开源项目

  • iOS逆向

  • Flutter开发

    • Dart - 抽象类的实例化
    • Flutter - 打印好用的Debug日志
    • Flutter - 混合开发
    • Flutter - 解决混合开发iOS脚本打包遇到的问题
    • Flutter - 低版本在iOS14上遇到的问题与解决方案
    • Flutter - 解决原生弹窗的触摸事件被Flutter响应的问题
    • Flutter - 实现列表上下拉切换header
    • Flutter - 获取ListView当前正在显示的Widget信息
    • Flutter - 列表滚动定位超强辅助库,墙裂推荐!🔥
    • Flutter - 快速实现聊天会话列表的效果,完美💯
    • Flutter - 聊天输入框更新文本时的必备优化点🔖
    • Flutter - 我给官方提PR,解决run命令卡住问题 😃
    • Flutter - 探索run命令到底做了什么 🤔
    • Flutter - 引擎调试(iOS篇)🛠
    • Flutter - 引擎调试bug到提交PR实战 🐞
    • Flutter - 船新升级😱支持观察第三方构建的滚动视图💪
    • Flutter - 瀑布流交替播放视频 🎞
    • Flutter - IM保持消息位置大升级(支持ChatGPT生成式消息) 🤖
    • Flutter - 滚动视图中的表单防遮挡 🗒
    • Flutter - 秒杀1/2曝光统计 📊
    • 一天内加入 Flutter 和 FlutterCandies 两大组织是什么体验 🧐
    • Flutter - 如何快速搓一个微信通讯录列表(azlist) 📓
    • Flutter - 混编项目集成Shorebird热更新🐦(安卓篇)
    • Flutter - 混编项目集成Shorebird热更新🐦(iOS篇)
    • Flutter - 解决返回原生页面时dispose方法未被触发的问题 🐞
    • Flutter - 升级3.19之后页面多次rebuild?🤨
    • Flutter - 热更新 Shorebird 1.0 正式版来了 🐦
    • Flutter - 使用Pigeon实现视频缓存插件 🐌
    • Flutter - 轻松搞定屏幕旋转功能 😎
    • Flutter - 解决Connection closed before full header was received
    • Flutter - 实现聊天键盘与功能面板的丝滑切换 🍻
      • 一、概述
      • 二、效果
      • 三、集成
      • 四、使用
        • 页面布局
        • 底部容器
      • 五、最后
    • Flutter - 支持观察NestedScrollView,兼容性更强 😈
    • Flutter - 聊天键盘与面板丝滑切换的强势升级 🍻
    • Flutter - 升级到3.24后页面还会多次rebuild吗?🧐
    • Flutter - 轻松实现PageView卡片偏移效果
    • Flutter - 轻松搞定炫酷视差(Parallax)效果
    • Flutter - 危!3.24版本苹果审核被拒!
    • Flutter - 子部件任意位置观察滚动数据
    • Flutter - iOS编译加速
    • Flutter - Xcode16 还原编译速度
  • 移动端
  • Flutter开发
LinXunFeng
2024-06-23
目录

Flutter - 实现聊天键盘与功能面板的丝滑切换 🍻

欢迎关注微信公众号:[FSA全栈行动 👋]

# 一、概述

相信大家接触【即时通信应用】的时候都会遇到这个问题,那就是如何去实现聊天页面的键盘和其它功能面板的丝滑切换,这种问题也有人向 Flutter 官方提出过 issue,如下这两个:

  • https://github.com/flutter/flutter/issues/121059 (opens new window)
  • https://github.com/flutter/flutter/issues/32583 (opens new window)

可以看到,从表情面板切到文本输入框时会抖动一下,影响用户体验。

但几年过去了依旧没有得到解决,再加上我自己也有这个小烦恼,所以我与 GitLqr (opens new window)(GitHub: https://github.com/GitLqr (opens new window))一起开发了这个 chat_bottom_container,来帮助我们快速实现这个丝滑切换的效果。

# 二、效果

这里先附上效果图,好让大家直观感受一下~

下面我们一起来看看怎么使用吧。

# 三、集成

将 chat_bottom_container 添加到你的 pubspec.yaml 文件中

dependencies:
  chat_bottom_container: latest_version

具体版本大家到 pub.dev 上复制粘贴最新的吧,附上链接:https://pub.dev/packages/chat_bottom_container (opens new window)

Android 端需要添加 jitpack 仓库到你的项目根目录下的 build.gradle 文件中:

allprojects {
  repositories {
    ...
    maven { url 'https://jitpack.io' }
  }
}

在需要使用的地方导入 chat_bottom_container :

import 'package:chat_bottom_container/chat_bottom_container.dart';

# 四、使用

# 页面布局

首先第一件事,确定整体的页面布局

@override
Widget build(BuildContext context) {
  return Scaffold(
    // 设置为 false
    resizeToAvoidBottomInset: false,
    body: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Expanded(
          child: ListView.builder(
            ...
          ),
        ),
        // 输入框视图
        _buildInputView(),
        // 底部容器
        _buildPanelContainer(),
      ],
    ),
  );
}

这里就两个注意点:

  1. 底部容器放在最底下
  2. resizeToAvoidBottomInset 必须设置为 false

# 底部容器

输入框视图的样式各种各样,这里就不说了,大家爱怎么实现都行,接下来我们来看看怎么使用 chat_bottom_container 这个库实现底部容器,代码如下:

/// 自定义底部面板类型
enum PanelType {
  // 收起
  none,
  // 键盘
  keyboard,
  // 表情
  emoji,
  // 其它工具
  tool,
}

/// chat_bottom_container 的控制器,用来告知 chat_bottom_container 需要切面板类型了
/// 注:这里传泛型传了 PanelType,是为了与外部的面板类型相关联
final controller = ChatBottomPanelContainerController<PanelType>();

/// 输入框的焦点对象
final FocusNode inputFocusNode = FocusNode();

/// 记录当前的底部面板类型
PanelType currentPanelType = PanelType.none;

Widget _buildPanelContainer() {
  return ChatBottomPanelContainer<PanelType>(
    controller: controller,
    inputFocusNode: inputFocusNode,
    otherPanelWidget: (type) {
      // 返回自定义的面板视图
      if (type == null) return const SizedBox.shrink();
      switch (type) {
        case PanelType.emoji: // 表情面板
          return _buildEmojiPickerPanel();
        case PanelType.tool: // 其它工具面板
          return _buildToolPanel();
        default:
          return const SizedBox.shrink();
      }
    },
    onPanelTypeChange: (panelType, data) {
      // 可用来记录当前的面板类型(该操作非必须~)
      // panelType: chat_bottom_container 内部定义的面板类型,就三种(.none|.keyboard|.other)
      // data: 外部自定义的底部面板类型
      switch (panelType) {
        case ChatBottomPanelType.none:
          currentPanelType = PanelType.none;
          break;
        case ChatBottomPanelType.keyboard:
          currentPanelType = PanelType.keyboard;
          break;
        case ChatBottomPanelType.other:
          if (data == null) return;
          switch (data) {
            case PanelType.emoji:
              currentPanelType = PanelType.emoji;
              break;
            case PanelType.tool:
              currentPanelType = PanelType.tool;
              break;
            default:
              currentPanelType = PanelType.none;
              break;
          }
          break;
      }
    },
    // 底部面板容器背景色
    panelBgColor: panelBgColor,
  );
}

chat_bottom_container 内部定义的面板类型,就三种

enum ChatBottomPanelType {
  // 无
  none,
  // 键盘
  keyboard,
  // 其它
  other,
}

因为 chat_bottom_container 并不关心你外部除了键盘外还有多少种面板类型,所以这里统一视为是 ChatBottomPanelType.other。

而我们外部开发者不可能不在乎,所以我们在点击表情面板按钮时,调用 controller.updatePanelType 去切换底部面板类型,并为 data 这个参数传入外部自定义的底部面板类型,如下代码所示

controller.updatePanelType(
  // 设置 ChatBottomPanelContainer 当前的底部面板类型
  // 可传入 ChatBottomPanelType.keyboard | ChatBottomPanelType.other | ChatBottomPanelType.none
  ChatBottomPanelType.other,
  // 回调给外部开发者自定义的 PanelType,当 ChatBottomPanelType.other 时必传
  data: PanelType.emoji, // PanelType.tool
);

所以上面提到的泛型就是为了关联 otherPanelWidget 和 onPanelTypeChange 回调中的类型,方便我们拿来使用。

# 五、最后

好了,上述便是该库的核心使用步骤, 我已将上述的 Flutter 聊天底部面板容器库发布至 GitHub: https://github.com/LinXunFeng/flutter_chat_packages/tree/main/packages/chat_bottom_container (opens new window) ,如果接入上有什么问题,可以在链接中查看 demo 演示代码。

开源不易,如果你也觉得这个库好用,请不吝给个 Star 👍 ,并多多支持!

本篇到此结束,感谢大家的支持,我们下次再见! 👋

#Dart#Flutter#Chat
Flutter - 解决Connection closed before full header was received
Flutter - 支持观察NestedScrollView,兼容性更强 😈

← Flutter - 解决Connection closed before full header was received Flutter - 支持观察NestedScrollView,兼容性更强 😈→

最近更新
01
Flutter - Xcode16 还原编译速度
04-05
02
AI - 免费的 Cursor 平替方案
03-30
03
Android - 2025年安卓真的闭源了吗
03-28
更多文章>
Theme by Vdoing | Copyright © 2020-2025 FSA全栈行动
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×