当我选择一个文本字段时,键盘会在它上面移动
Posted
技术标签:
【中文标题】当我选择一个文本字段时,键盘会在它上面移动【英文标题】:When I select a Textfield the keyboard moves over it 【发布时间】:2018-11-17 02:15:20 【问题描述】:当我选择一个文本字段时,将显示键盘,但键盘隐藏了我选择的文本字段。有人有解决方案吗?
【问题讨论】:
你可能想关注这个问题github.com/flutter/flutter/issues/10826 看看这个对我有用。无需动画。 ***.com/a/58209885/15035067 我的解决方案here at this thread 解决了这个问题。它非常简短,不需要动画。 【参考方案1】:编写动画并在 TextField 获得焦点时向上移动 TextField 容器。
有关制作动画的知识,请参阅: Composing Animations and Chaining Animations in Dart's Flutter Framework
使用 Flutter 的 FocusNode 检测 TextField 上的焦点
编辑:
在这里,我写了一个完全符合您要求的示例:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Animation Demo',
theme: new ThemeData(
primaryColor: new Color(0xFFFF0000),
),
home: new FormDemo(),
);
class FormDemo extends StatefulWidget
@override
_FormDemoState createState() => _FormDemoState();
class _FormDemoState extends State<FormDemo> with SingleTickerProviderStateMixin
AnimationController _controller;
Animation _animation;
FocusNode _focusNode = FocusNode();
@override
void initState()
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_animation = Tween(begin: 300.0, end: 50.0).animate(_controller)
..addListener(()
setState(() );
);
_focusNode.addListener(()
if (_focusNode.hasFocus)
_controller.forward();
else
_controller.reverse();
);
@override
void dispose()
_controller.dispose();
_focusNode.dispose();
super.dispose();
@override
Widget build(BuildContext context)
return Scaffold(
resizeToAvoidBottomPadding: false, // this avoids the overflow error
appBar: AppBar(
title: Text('TextField Animation Demo'),
),
body: new InkWell( // to dismiss the keyboard when the user tabs out of the TextField
splashColor: Colors.transparent,
onTap: ()
FocusScope.of(context).requestFocus(FocusNode());
,
child: Container(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
SizedBox(height: _animation.value),
TextFormField(
decoration: InputDecoration(
labelText: 'I move!',
),
focusNode: _focusNode,
)
],
),
),
),
);
【讨论】:
你能给我发一份代码示例吗? 谢谢,但我的动画有问题。 Tween.animate(_controller)
后错误会消失
对不起,我看到了我的错误。感谢您的帮助!
您应该在使用动画时使用 dispose:“最佳实践是任何具有 dispose 方法的对象都应在其 dispose 方法中调用它拥有的所有也具有 dispose 方法的对象的 dispose 方法。一般来说,如果你完成了那个对象,总是用这样的方法调用一个对象的 dispose。” @伊恩·希克森【参考方案2】:
只需在此剪切并粘贴您的正文代码 -
SingleChildScrollView(
child: Stack(
children: <Widget>[
// your body code
],
),
),
【讨论】:
这是他们的方式。除非您确定自己遇到了这种情况不起作用,否则请让 Flutter 的默认行为为您解决问题。 这就是方式 这不起作用。这将使内容与其内容一起滚动,问题不是无法滚动,而是文本字段没有弹出键盘上方。这些我都试过了。还在苦苦挣扎。【参考方案3】:实现这一点的一个非常简单的方法是简单地使用 MediaQuery 来获取底部视图插图。如下所示:
...
return Row(
children: <Widget>[
TextField(
decoration: InputDecoration.collapsed(hintText: "Start typing ..."),
controller: _chatController,
),
SizedBox(
height: MediaQuery.of(Context).viewInsets.bottom,
),
],
);
...
希望对你有帮助!
【讨论】:
【参考方案4】:<activity
android:name="..ActivityName"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"/>
仅适用于安卓 如果您使用 FlutterFragment,请为 Activity 添加 configChanges 和 windowSoftInputMode。
另一种方式 将您的 TextField 添加到 ListView
ListView(
children: <Widget>[
TextField(),
TextField(),
]
)
【讨论】:
【参考方案5】: Scaffold(
resizeToAvoidBottomInset: true,
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
)
],
),
),
)
);
// resizeToAvoidBottomPadding: false isDeprecated
使用 resizeToAvoidBottomInset: true。
【讨论】:
这是最好的答案!! @Watanabe.N 我知道现在回复您的评论为时已晚。我只是想问你,你仍然面临同样的问题,或者现在你的问题已经解决了。如果仍然面临同样的问题,请告诉我,以便我可以为您提供同样的帮助。 @AnkushModi 谢谢你的好意。就我而言,最后,resizeToAvoidBottomInset
解决了问题!【参考方案6】:
最简单的方法就是用
SingleChildScrollView( ... )
当文本域位于页面底部并且出现键盘时,文本域会自动向上滚动。然后可以在键盘正上方输入文本。
【讨论】:
【参考方案7】:我的路
Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/Bg img.png'), fit: BoxFit.fill)),
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
.............
这个模板有一些优点:
出现键盘时向上移动内容 在滚动视图中使用 spaceBetween 的列 背景是手机屏幕,永远不会改变键盘 ups 事件【讨论】:
【参考方案8】:如果您在NestedScrollView
中有CustomScrollview
,则上述方法不起作用。
首先,您需要给 TextField 一个 focusNode。
TextField(focusNode:_focusNode(),
...);
使用NestedScrollViewState 访问NestedScrollView
的innerScrollController
。您可以查看示例here 了解如何获取innerScrollController。声明一个 globalKey 并将其分配给 NestedScrollView。
body: NestedScrollView(
key: globalKey,
...)
设置 focusNode
监听器以监听文本字段何时被激活并相应地为 innerScrollController 设置动画。
void initState()
super.initState();
_focusNode.addListener(()
if (_focusNode.hasFocus)
double innerOffSet = globalKey.currentState.innerController.offset;
if(innerOffSet < 100)
globalKey.currentState.innerController.jumpTo(innerOffSet+100);
);
【讨论】:
【参考方案9】:var _contentController;
void _settingModalBottomSheet(BuildContext context, String initialText)
_contentController = new TextEditingController(text: initialText);
showModalBottomSheet(
context: context,
isDismissible: true,
builder: (BuildContext bc)
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: 40,
margin: EdgeInsets.only(left: 4, right: 4, bottom: 8),
decoration: BoxDecoration(
color: AppColor.bgTextFieldComment,
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 24),
child: TextField(
focusNode: _contentFocusNode,
autofocus: true,
controller: _contentController,
decoration: InputDecoration(
hintText: 'Enter Content',
border: InputBorder.none,
fillColor: AppColor.bgTextFieldComment,
),
keyboardType: TextInputType.multiline,
maxLines: null,
style: TextStyle(
color: Colors.black87,
fontSize: 16,
fontStyle: FontStyle.normal,
),
)),
),
InkWell(
child: Padding(
padding: EdgeInsets.only(left: 4, right: 4),
child: Icon(
Icons.send,
color: Colors.blue,
),
),
onTap: ()
// do ON TAP
,
),
],
),
),
SizedBox(
height: MediaQuery.of(bc).viewInsets.bottom,
),
],
);
,).then((value)
print('Exit Modal');
);
print('request focus');
_contentFocusNode.requestFocus();
【讨论】:
【参考方案10】:在我的情况下,我必须将@Javid Noutash
给出的答案结合使用AnimationController
以及scrollPadding
的TextFormField
属性。
代码:
在构建方法中添加这一行
double bottomInsets = MediaQuery.of(context).viewInsets.bottom;
添加scrollPadding
属性
return ListView(
children:[
...widgets,
Container(
margin:EdgeInsets.only(
top:1.0,
left:1.0,
right:1.0,
bottom:_focusNode.hasFocus && bottomInsets != 0?
_animation.value : 1.0),
child:TextFormField(
decoration: InputDecoration(
labelText: 'I move!',
),
focusNode: _focusNode,
scrollPadding: EdgeInsets.only(bottom:bottomInsets + 40.0),
),
),
]
);
注意:将此代码与@Javid Noutash
的代码结合起来
【讨论】:
【参考方案11】:代替TextField
,使用TextFormField
并用TextFormField
到Form
的列表包装小部件:
Form(
child: Column(
children: <Widget> [
TextFormField(),
TextFormField(),
...
TextFormField(),
]
)
)
【讨论】:
【参考方案12】:当父小部件是 Material 而其他小部件位于 ListView 内时,我遇到了同样的问题。当我在没有任何额外代码的情况下将父小部件更改为 Scaffold 并且 TextField(在我的情况下为 TextFormField)自动显示在键盘上方时,问题得到了解决。因此,如果您遇到此问题,只需确保将 Scaffold 作为主要小部件。
【讨论】:
【参考方案13】:在我的情况下查看代码非常容易
Column(
children: [
Expanded(
child:// Top View,
),
postSend // edittext. and button
],
)
【讨论】:
【参考方案14】:您可以轻松尝试使用灵活的小部件,只需用它包装您的小部件
Flexible(
child: Image(
image :
AssetImage('assets/logo.png'),
),
),
【讨论】:
【参考方案15】:将您的小部件包装到 Padding 中并设置 padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
【讨论】:
以上是关于当我选择一个文本字段时,键盘会在它上面移动的主要内容,如果未能解决你的问题,请参考以下文章