日期
2025-12-23
问题描述
在聊天页面中,当键盘弹出时,输入框会出现明显的”弹跳”现象:
- 键盘升起过程中,输入框被键盘遮挡
- 键盘动画结束后,输入框突然跳到键盘上方
- 整个过程不平滑,使用体验很差
尝试过的方案(均失败)
1. SafeArea + resizeToAvoidBottomInset: true
SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: true,
...
),
)结果: 仍然弹跳
2. AnimatedPadding 手动处理
AnimatedPadding(
duration: Duration(milliseconds: 200),
padding: EdgeInsets.only(bottom: viewInsets.bottom),
...
)结果: 仍然弹跳(因为 viewInsets.bottom 本身延迟更新)
3. 参考 DifyChat 项目结构
尝试复制其 SafeArea 包裹方式 结果: 仍然弹跳
4. 简化输入框,移除所有复杂逻辑
结果: 仍然弹跳
5. 禁用 edge-to-edge 模式
修改 styles.xml 添加 windowOptOutEdgeToEdgeEnforcement
结果: 仍然弹跳(已回滚)
6. ListView reverse: true
ListView.builder(
reverse: true,
...
)结果: 仍然弹跳
7. chat_bottom_container 包
使用原生代码获取键盘高度的第三方包 结果: 仍然弹跳
最终解决方案
参考 kelivo 项目,发现关键在于正确设置 edge-to-edge 模式:
main.dart 添加系统 UI 配置
import 'package:flutter/services.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// 启用 edge-to-edge 模式,让内容延伸到系统栏下方
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
// 设置系统栏透明
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarDividerColor: Colors.transparent,
));
// ... 其他初始化
runApp(MyApp());
}Scaffold 使用默认配置
Scaffold(
resizeToAvoidBottomInset: true, // 默认值,让 Scaffold 处理键盘避让
body: Column(
children: [
Expanded(child: ListView(...)),
InputBar(),
],
),
)关键发现
-
Flutter 3.38+ 的 edge-to-edge 处理
- 新版 Flutter 需要明确设置
SystemUiMode.edgeToEdge - 同时需要设置系统栏透明
- 这样 Flutter 才能正确处理键盘动画
- 新版 Flutter 需要明确设置
-
不要同时使用多个键盘避让方案
- 只用 Scaffold 的
resizeToAvoidBottomInset: true - 不要额外添加手动 padding
- 不要使用第三方键盘处理包
- 只用 Scaffold 的
-
参考项目
- kelivo 项目使用 Flutter SDK ^3.8.1
- 使用最简单的 Scaffold 默认配置
- 关键是 main.dart 中的系统 UI 设置
相关文件
lib/main.dart- 添加 edge-to-edge 配置lib/ui/chat_page.dart- 使用标准 Scaffold 结构
总结
问题的根本原因是 Flutter 3.x 需要明确设置 edge-to-edge 模式,否则键盘动画与布局调整不同步。解决方案非常简单,只需要在 main.dart 中添加两行系统 UI 配置即可。