【问题标题】:When I select a Textfield the keyboard moves over it当我选择一个文本字段时,键盘会在它上面移动
【发布时间】:2018-11-17 02:15:20
【问题描述】:

当我选择一个文本字段时,将显示键盘,但键盘隐藏了我选择的文本字段。有人有解决方案吗?

【问题讨论】:

标签: dart flutter


【解决方案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,则上述方法不起作用。

          1. 首先,您需要给 TextField 一个 focusNode。

            TextField(focusNode:_focusNode(),
              ...);
            
          2. 使用NestedScrollViewState 访问NestedScrollViewinnerScrollController。您可以查看示例here 了解如何获取innerScrollController。声明一个 globalKey 并将其分配给 NestedScrollView。

             body: NestedScrollView(
                key: globalKey,
                ...)
            
          3. 设置 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),

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2020-05-21
                          • 2019-10-19
                          • 1970-01-01
                          • 2014-10-30
                          • 1970-01-01
                          • 2011-08-23
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多