在 Flutter 中只让一个小部件漂浮在键盘上方
Posted
技术标签:
【中文标题】在 Flutter 中只让一个小部件漂浮在键盘上方【英文标题】:Make only one widget float above the keyboard in Flutter 【发布时间】:2019-11-17 17:50:59 【问题描述】:我想在键盘可见时在键盘上方显示一个“关闭键盘”按钮。
我知道 resizeToAvoidBottomInset 会影响键盘与应用程序其余部分的交互方式,但它并不能完全满足我的要求。
我有一个背景图像和其他小部件(未在下面的示例中显示),它们在显示键盘时不应调整大小和移动。当 resizeToAvoidBottomInset
属性设置为 false 时,这是一个正常的行为。
不过,我想添加一个应该出现在键盘上方的按钮。
我该怎么做?我只希望一个小部件悬浮在键盘上方,而不是所有应用程序。
这是一个示例代码:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
var home = MyHomePage(title: 'Flutter Demo Home Page');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: home,
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
@override
Widget build(BuildContext context)
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: _getBody(),
floatingActionButton: FloatingActionButton(
onPressed: () ,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
Widget _getBody()
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
【问题讨论】:
【参考方案1】:您的 Positioned
小部件的 bottom
为 0,替换为适当的值即可。
MediaQuery.of(context).viewInsets.bottom
将为您提供系统 UI(在本例中为键盘)覆盖的高度值。
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
var home = MyHomePage(title: 'Flutter Demo Home Page');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: home,
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
@override
Widget build(BuildContext context)
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: _getBody(),
floatingActionButton: FloatingActionButton(
onPressed: () ,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
Widget _getBody()
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
Positioned(
bottom: MediaQuery.of(context).viewInsets.bottom,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
【讨论】:
这是如何工作的?每次键盘出现后它都会自然重建吗?【参考方案2】:2022 年更新
合并了一个 PR,它提供了用于关闭/打开键盘的平台同步动画。请参阅PR in effect here。
详细解答
为了实现基于键盘可见性的动画填充,以下是对 @10101010 的最佳答案的一些修改:
如果您希望在键盘更改可见性时更改bottom
以进行动画处理并且您希望在浮动子项下有额外的填充,那么:
1- 使用keyboard_visibilityflutter pub
在键盘出现/消失时收听,如下所示:
bool isKeyboardVisible = false;
@override
void initState()
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible)
isKeyboardVisible = visible;
,
);
您可以选择编写自己的本机插件,但它已经存在,您可以检查 pub 的 git repo。
2- 在您的AnimatedPostioned
中使用可见性标志:
对于微调的动画填充,如下所示:
Widget _getBody()
double bottomPadding = 0;
if (isKeyboardVisible)
// when keyboard is shown, our floating widget is above the keyboard and its accessories by `16`
bottomPadding = MediaQuery.of(context).viewInsets.bottom + 16;
else
// when keyboard is hidden, we should have default spacing
bottomPadding = 48; // MediaQuery.of(context).size.height * 0.15;
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
AnimatedPositioned(
duration: Duration(milliseconds: 500),
bottom: bottomPadding,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
3- 特定于键盘的动画曲线和同步动画的持续时间
目前这仍然是known ongoing issue
【讨论】:
【参考方案3】:您可以使用 Scaffold 的 bottomSheet 参数,它保持一个持久的底部工作表。请参阅下面的代码。
class InputScreen extends StatelessWidget
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(title: const Text('Close')),
bottomSheet: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
color: Colors.black,
child: const SizedBox(width: double.infinity, height: 10)),
body: Column(
children: [
const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter your input here',
),
),
ElevatedButton(
onPressed: () ,
child: const Text('Submit'),
),
],
),
);
【讨论】:
【参考方案4】:检查这个package, 它可以在键盘上方显示一个关闭按钮。
【讨论】:
该软件包很有趣,并且与我想做的事情相同,但是在我的情况下,@10101010 提到的解决方案更容易实现。以上是关于在 Flutter 中只让一个小部件漂浮在键盘上方的主要内容,如果未能解决你的问题,请参考以下文章
Flutter - 在 AlertDialog 小部件之外点击后关闭系统键盘
Flutter 使用 Provider 时出现“EditableText 上方不存在覆盖小部件”错误