如何在键盘外观上为 Flutter 布局设置动画
Posted
技术标签:
【中文标题】如何在键盘外观上为 Flutter 布局设置动画【英文标题】:How to animate Flutter layout on keyboard appearance 【发布时间】:2019-07-01 00:14:23 【问题描述】:我正在构建一个 Flutter 应用,主要用于 ios。
我的一个视图有一个文本字段,当您点击它时会出现 iOS 键盘。问题是 - 布局不会像在原生 iOS 应用程序中那样平滑地变化。相反,它会在键盘打开动画结束之前立即跳转到最终可用的屏幕高度。
我尝试将我的 SafeArea 元素包装在 AnimatedSize
和 AnimatedContainer
中 - 它没有帮助。
我的布局代码:
SafeArea(child:
Column(children:[
TextField(...)
])
)
如何让键盘出现时布局平滑调整大小?
预期:
实际
【问题讨论】:
你能用 gif/截图更新你的问题吗? @miguelpruivo 附上 gif。由于 FPS 速率较低,差异并不那么明显,但我希望很清楚我想要实现的目标 - 出现键盘时平滑调整 SafeArea 的大小。 您是否尝试将输入字段仅包装在AnimatedContainer
中?您可能想用一些代码编辑您的问题。发生的情况是,当您启动键盘时,键盘正在使用底部的viewInsets
,并且正在重建视图以匹配更改,但实际上并没有与之一起动画。不过这是个好问题。
调试模式有可能吗?尝试发布 apk 或使用 --profile
你可以在github上查看这个问题https://github.com/flutter/flutter/issues/19279
这可能会有所帮助
【参考方案1】:
您需要使用keyboard_visibility 包并使用它来触发您的AnimatedContainer 或AnimatedPadding
bool _isKeyboardActive = false;
@override
void initState()
super.initState();
//add keyboard visibility Listener
KeyboardVisibility.onChange.listen((event)
setState(()
_isKeyboardActive = event;
);
);
Widget build(BuildContext context)
return AnimatedContainer(
width: _isKeyboardActive ? 200 : MediaQuery.of(context).size.width,
height: 60,
color: Colors.red,
duration: Duration(milliseconds: 600)
)
以此为基础。
【讨论】:
【参考方案2】:使用 AnimatedPadding Widget 可以实现所需的输出,虽然这并不完美,但总比没有好:d
Open issue as of 15/03/21, for reference
import 'dart:math';
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
class MyWidget extends StatelessWidget
@override
Widget build(BuildContext context)
return SafeArea(
bottom: false,
child: Scaffold(
// !!! Important part > to disable default scaffold insets
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text("Appbar Title"),
),
body: Stack(
children: [
Scrollbar(
child: ListView.builder(
padding: EdgeInsets.all(0.0),
itemCount: 30,
itemBuilder: (context, i)
return Container(
height: 100,
width: double.infinity,
color: Colors
.primaries[Random().nextInt(Colors.primaries.length)],
);
,
),
),
Align(
alignment: Alignment.bottomLeft,
child: AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
// You can change the duration and curve as per your requirement:
duration: const Duration(milliseconds: 200),
curve: Curves.decelerate,
child: InputField()),
)
],
)),
);
class InputField extends StatefulWidget
InputField(Key key) : super(key: key);
@override
_InputFieldState createState() => _InputFieldState();
class _InputFieldState extends State<InputField>
@override
Widget build(BuildContext context)
return Container(
color: Colors.grey[100],
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
SizedBox(
width: 60,
child: Icon(Icons.add_a_photo),
),
Flexible(
child: TextField(
style: Theme.of(context).textTheme.bodyText1,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter text...',
),
),
),
SizedBox(
width: 60,
child: Icon(Icons.send),
),
],
),
);
输出 ->
【讨论】:
【参考方案3】:我使用类似的东西:
AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: ....
)
这会根据 viewInsets(软件键盘高度)为填充设置动画。
【讨论】:
虽然这段代码可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因【参考方案4】:您可以使用此包keyboard_visibility 并收听keyboard visibility
。然后你可以给出你的逻辑来实现你的功能,就像你可以缩短主页container
高度一样。那并不完美。但我认为这是目前唯一的方法。
【讨论】:
【参考方案5】:您应该尝试像这样设置resizeToAvoidBottomPadding: false
:
return Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomPadding: false,
【讨论】:
以上是关于如何在键盘外观上为 Flutter 布局设置动画的主要内容,如果未能解决你的问题,请参考以下文章