当我选择一个文本字段时,键盘会在它上面移动

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 的值类型不能赋值给动画类型的变量。 在 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 添加 configChangeswindowSoftInputMode

另一种方式 将您的 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 访问NestedScrollViewinnerScrollController。您可以查看示例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 以及scrollPaddingTextFormField 属性。 代码:

在构建方法中添加这一行

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 并用TextFormFieldForm 的列表包装小部件:

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),

【讨论】:

以上是关于当我选择一个文本字段时,键盘会在它上面移动的主要内容,如果未能解决你的问题,请参考以下文章

出现键盘时移动文本字段会覆盖(Swift)中的顶部文本字段

隐藏在键盘后面的文本字段

JQuery Mobile:单击文本字段时如何禁用默认键盘?

使用 Swift 使用键盘移动视图

在 iPad 上,如何防止模态视图在键盘呈现时向上移动?

将一个文本字段移动到另一个文本字段时键盘熄灭