【问题标题】:How can I dismiss the on screen keyboard?如何关闭屏幕键盘?
【发布时间】:2019-01-10 15:24:05
【问题描述】:

我正在使用 TextFormField 收集用户输入,当用户按下 FloatingActionButton 表示完成时,我想关闭屏幕键盘。

如何让键盘自动消失?

import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  MyHomePageState createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  TextEditingController _controller = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.send),
        onPressed: () {
          setState(() {
            // send message
            // dismiss on screen keyboard here
            _controller.clear();
          });
        },
      ),
      body: new Container(
        alignment: FractionalOffset.center,
        padding: new EdgeInsets.all(20.0),
        child: new TextFormField(
          controller: _controller,
          decoration: new InputDecoration(labelText: 'Example Text'),
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

void main() {
  runApp(new MyApp());
}

【问题讨论】:

标签: dart flutter


【解决方案1】:

注意:此答案已过时。 See the answer for newer versions of Flutter.

您可以通过将TextFormField 的焦点移至未使用的FocusNode 来关闭键盘:

FocusScope.of(context).requestFocus(FocusNode());

【讨论】:

  • 你会在哪里实现这个代码?在 TextFormField 中;也许在onChanged: 之后或在您的自定义按钮的操作中?
  • @CharlesJr 我在按钮的操作中做到了。
  • 如果你愿意,可以使用我的包:) pub.dartlang.org/packages/keyboard_actions
  • 这是在 Flutter v1.7.8 之前的版本 - 请参阅答案 stackoverflow.com/a/56946311/8696915,它给出了 FocusScope.of(context).unfocus()
  • 如果您可以访问 .unfocus(),请不要这样做,因为它会导致内存泄漏。新的 FocusNode() 永远不会被清理。查看关于 .unfocus() 的评论
【解决方案2】:

使用 FocusScope 的解决方案对我不起作用。 我找到了另一个:

import 'package:flutter/services.dart';

SystemChannels.textInput.invokeMethod('TextInput.hide');

它解决了我的问题。

【讨论】:

  • 调用它不会为我隐藏键盘。它应该同时在 Android 和 iOS 上运行吗?
  • 在 iOS(12.1、iPhone 5s)和 Android (Pixel 3) 上为我工作
  • 你把这个放在哪里?我尝试将其添加为应用程序中的第一段代码,但它没有做任何事情。
  • 你是什么意思 - “代码的第一位”?以build方法为例。
  • 数字键盘有对应的吗?
【解决方案3】:

以上解决方案都不适用于我。

Flutter 建议这样做 - 将您的小部件放在 new GestureDetector() 内,点击将隐藏键盘和 onTap 使用 FocusScope.of(context).requestFocus(new FocusNode())

class Home extends StatelessWidget {
@override
  Widget build(BuildContext context) {
    var widget = new MaterialApp(
        home: new Scaffold(
            body: new Container(
                height:500.0,
                child: new GestureDetector(
                    onTap: () {
                        FocusScope.of(context).requestFocus(new FocusNode());
                    },
                    child: new Container(
                        color: Colors.white,
                        child:  new Column(
                            mainAxisAlignment:  MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,

                            children: [
                                new TextField( ),
                                new Text("Test"),                                
                            ],
                        )
                    )
                )
            )
        ),
    );

    return widget;
}}

【讨论】:

    【解决方案4】:

    您可以使用FocusNode 类中的unfocus() 方法。

    import 'package:flutter/material.dart';
    
    class MyHomePage extends StatefulWidget {
      MyHomePageState createState() => new MyHomePageState();
    }
    
    class MyHomePageState extends State<MyHomePage> {
      TextEditingController _controller = new TextEditingController();
      FocusNode _focusNode = new FocusNode(); //1 - declare and initialize variable
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(),
          floatingActionButton: new FloatingActionButton(
            child: new Icon(Icons.send),
            onPressed: () {
                _focusNode.unfocus(); //3 - call this method here
            },
          ),
          body: new Container(
            alignment: FractionalOffset.center,
            padding: new EdgeInsets.all(20.0),
            child: new TextFormField(
              controller: _controller,
              focusNode: _focusNode, //2 - assign it to your TextFormField
              decoration: new InputDecoration(labelText: 'Example Text'),
            ),
          ),
        );
      }
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          home: new MyHomePage(),
        );
      }
    }
    
    void main() {
      runApp(new MyApp());
    }
    

    【讨论】:

    • 嗨!如果您可以edit您的答案为您的答案添加更多上下文,那将是最好的。
    • 编码最少的最佳方案
    • 是的,如果点击特定的小部件,它会移除焦点。无法将其添加到我的应用上的每个小部件。
    • 点击小部件只是调用unfocus 方法的一种方式。如果您不想在您的应用上发送垃圾邮件,您可以使用不同的方式,例如 TextFormField 更改事件或反应模式,这取决于您应用的架构。
    【解决方案5】:

    在 Flutter 中,一切都是小部件,我决定将 SystemChannels.textInput.invokeMethod('TextInput.hide');FocusScope.of(context).requestFocus(FocusNode()); 方法包装在一个简短的实用模块中,其中包含一个小部件和一个 mixin。

    使用小部件,您可以使用KeyboardHider 小部件包装任何小部件(使用良好的 IDE 支持时非常方便):

    class SimpleWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return KeyboardHider(
          /* Here comes a widget tree that eventually opens the keyboard,
           * but the widget that opened the keyboard doesn't necessarily
           * takes care of hiding it, so we wrap everything in a
           * KeyboardHider widget */
          child: Container(),
        );
      }
    }
    

    使用 mixin,您可以在任何交互时触发从任何状态或小部件中隐藏键盘:

    class SimpleWidget extends StatefulWidget {
      @override
      _SimpleWidgetState createState() => _SimpleWidgetState();
    }
    
    class _SimpleWidgetState extends State<SimpleWidget> with KeyboardHiderMixin {
      @override
      Widget build(BuildContext context) {
        return RaisedButton(
          onPressed: () {
            // Hide the keyboard:
            hideKeyboard();
            // Do other stuff, for example:
            // Update the state, make an HTTP request, ...
          },
        );
      }
    }
    

    只需创建一个keyboard_hider.dart 文件,小部件和mixin 就可以使用了:

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    /// Mixin that enables hiding the keyboard easily upon any interaction or logic
    /// from any class.
    abstract class KeyboardHiderMixin {
      void hideKeyboard({
        BuildContext context,
        bool hideTextInput = true,
        bool requestFocusNode = true,
      }) {
        if (hideTextInput) {
          SystemChannels.textInput.invokeMethod('TextInput.hide');
        }
        if (context != null && requestFocusNode) {
          FocusScope.of(context).requestFocus(FocusNode());
        }
      }
    }
    
    /// A widget that can be used to hide the text input that are opened by text
    /// fields automatically on tap.
    ///
    /// Delegates to [KeyboardHiderMixin] for hiding the keyboard on tap.
    class KeyboardHider extends StatelessWidget with KeyboardHiderMixin {
      final Widget child;
    
      /// Decide whether to use
      /// `SystemChannels.textInput.invokeMethod('TextInput.hide');`
      /// to hide the keyboard
      final bool hideTextInput;
      final bool requestFocusNode;
    
      /// One of hideTextInput or requestFocusNode must be true, otherwise using the
      /// widget is pointless as it will not even try to hide the keyboard.
      const KeyboardHider({
        Key key,
        @required this.child,
        this.hideTextInput = true,
        this.requestFocusNode = true,
      })  : assert(child != null),
            assert(hideTextInput || requestFocusNode),
            super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () {
            hideKeyboard(
              context: context,
              hideTextInput: hideTextInput,
              requestFocusNode: requestFocusNode,
            );
          },
          child: child,
        );
      }
    }
    

    【讨论】:

      【解决方案6】:

      以下代码帮助我隐藏键盘

         void initState() {
         SystemChannels.textInput.invokeMethod('TextInput.hide');
         super.initState();
         }
      

      【讨论】:

      • 对我来说,这比添加 FocusScope.of(context).unfocus() 的解决方案效果更好,因为该解决方案让我进入了显示和隐藏键盘的循环
      • 这对我来说效果最好。我从另一个屏幕打开了一个键盘,我认为焦点处于奇怪的状态,所以只有这种方法有效。谢谢!!!!
      • 这比以前的解决方案要优雅得多。最重要的是,这可以包含在 override dispose 方法中,以保证无论何时释放小部件(例如在对话框中非常有用),屏幕上的键盘输入都会适当地关闭。
      • 非常简单n不错的解决方案..
      【解决方案7】:

      从 Flutter v1.7.8+hotfix.2 开始,要走的路是:

      FocusScope.of(context).unfocus();
      

      Comment 对此进行公关:

      既然 #31909 (be75fb3) 已经登陆,您应该使用 FocusScope.of(context).unfocus() 而不是 FocusScope.of(context).requestFocus(FocusNode()),因为 FocusNodes 是 ChangeNotifiers,应妥善处理。

      -> 不要再使用̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶

       F̶o̶c̶u̶s̶S̶c̶o̶p̶e̶.̶o̶f̶(̶c̶o̶n̶t̶e̶x̶t̶)̶.̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶)̶;̶
      

      阅读更多关于the FocusScope class in the flutter docs的信息。

      【讨论】:

      • 我遇到的问题是在离开文本字段打开相机时,键盘并不总是被关闭并与相机重叠。该解决方案实际上确实移除了焦点,但随后焦点返回到文本字段并且问题仍然存在。将焦点移至未使用的 FocusNode 即可解决此问题。
      【解决方案8】:
      _dismissKeyboard(BuildContext context) {
         FocusScope.of(context).requestFocus(new FocusNode());
      }
      
      @override
      Widget build(BuildContext context) {
      
      return new GestureDetector(
          onTap: () {
          this._dismissKeyboard(context);
          },
          child: new Container(
          color: Colors.white,
          child: new Column(
              children: <Widget>[/*...*/],
          ),
          ),
       );
      }
      

      【讨论】:

        【解决方案9】:
        GestureDetector(
                  onTap: () {
                    FocusScope.of(context).unfocus();
                  },
                  child:Container(
            alignment: FractionalOffset.center,
            padding: new EdgeInsets.all(20.0),
            child: new TextFormField(
              controller: _controller,
              decoration: new InputDecoration(labelText: 'Example Text'),
            ),
          ), })
        

        点击手势试试这个

        【讨论】:

          【解决方案10】:

          看起来不同版本的不同方法。我正在使用 Flutter v1.17.1,以下对我有用。

          onTap: () {
              FocusScopeNode currentFocus = FocusScope.of(context);
              if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
                 currentFocus.focusedChild.unfocus();
              }
          }
          

          【讨论】:

            【解决方案11】:

            尝试使用 TextEditingController。 一开始,

                final myController = TextEditingController();
                 @override
              void dispose() {
                // Clean up the controller when the widget is disposed.
                myController.dispose();
                super.dispose();
              }
            

            在新闻发布会上,

            onPressed: () {
                        myController.clear();}
            

            这将关闭键盘。

            【讨论】:

            • 它只清除控制器的文本。它不会使 TextField 失去焦点。
            【解决方案12】:

            对于 Flutter 1.17.3(截至 2020 年 6 月的稳定通道),使用

            FocusManager.instance.primaryFocus.unfocus();
            

            【讨论】:

            • 经过测试并适用于 Flutter:1.24.0。以及 iOS 14.0 和 Android 版本 11 模拟器。
            • 效果很好。使用 null-safety,在 primaryFocus 上使用可选链接,如下所示:FocusManager.instance.primaryFocus?.unfocus();
            • 这对我来说适用于颤振版本:2.0.2
            【解决方案13】:

            总而言之,这是 Flutter 1.17 的可行解决方案:

            像这样包装你的小部件:

            GestureDetector(
                    onTap: FocusScope.of(context).unfocus,
                    child: YourWidget(),
            );
            

            【讨论】:

              【解决方案14】:

              要关闭键盘(1.7.8+hotfix.2 及更高版本)只需调用以下方法:

              FocusScope.of(context).unfocus();
              

              一旦 FocusScope.of(context).unfocus() 方法在关闭键盘之前已经检查是否有焦点,则不需要检查它。但如果您需要它,只需调用另一个上下文方法:FocusScope.of(context).hasPrimaryFocus

              【讨论】:

                【解决方案15】:

                您还可以为您的文本字段声明一个 focusNode,完成后您可以在该 focusNode 上调用 unfocus 方法 并丢弃它

                class MyHomePage extends StatefulWidget {
                  MyHomePageState createState() => new MyHomePageState();
                }
                
                class MyHomePageState extends State<MyHomePage> {
                  TextEditingController _controller = new TextEditingController();
                
                /// declare focus
                  final FocusNode _titleFocus = FocusNode();
                
                  @override
                  void dispose() {
                    _titleFocus.dispose();
                  }
                
                  @override
                  Widget build(BuildContext context) {
                    return new Scaffold(
                      appBar: new AppBar(),
                      floatingActionButton: new FloatingActionButton(
                        child: new Icon(Icons.send),
                        onPressed: () {
                          setState(() {
                            // send message
                            // dismiss on screen keyboard here
                
                            _titleFocus.unfocus();
                            _controller.clear();
                          });
                        },
                      ),
                      body: new Container(
                        alignment: FractionalOffset.center,
                        padding: new EdgeInsets.all(20.0),
                        child: new TextFormField(
                          controller: _controller,
                          focusNode: _titleFocus,
                          decoration: new InputDecoration(labelText: 'Example Text'),
                        ),
                      ),
                    );
                  }
                }
                

                【讨论】:

                  【解决方案16】:

                  对我来说,App 小部件上方的 Listener 是我发现的最佳方法:

                  Listener(
                    onPointerUp: (_) {
                      FocusScopeNode currentFocus = FocusScope.of(context);
                      if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
                        currentFocus.focusedChild.unfocus();
                      }
                    },
                    child: MaterialApp(
                      title: 'Flutter Test App',
                      theme: theme,
                      ...
                    ),
                  )
                  

                  【讨论】:

                  • 这在 iOS 中对我有用,我不知道这是正确的做法。
                  【解决方案17】:

                  这可能会简化情况。以下代码仅在键盘打开时才有效

                  if(FocusScope.of(context).isFirstFocus) {
                   FocusScope.of(context).requestFocus(new FocusNode());
                  }
                  

                  【讨论】:

                    【解决方案18】:

                    FocusScope.of(context).unfocus() 与过滤后的 listView 一起使用时有一个缺点。 除了这么多细节和简洁,使用https://pub.dev/packages/keyboard_dismisser中的keyboard_dismisser包将解决所有问题。

                    【讨论】:

                    【解决方案19】:

                    如果你使用CustomScrollView,就放吧,

                    keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
                    

                    【讨论】:

                      【解决方案20】:

                      您可以使用“GestureDetector”包装您的小部件,然后将“FocusScope.of(context).unfocus()”分配给它的 onTap 函数

                      GestureDetector(
                       onTap: () => FocusScope.of(context).unfocus(),
                       child: child,
                      );
                      

                      【讨论】:

                        【解决方案21】:

                        如果您的键盘仍然无法关闭,请不要忘记将 focusNode 添加到 TextField。上面的信息很有帮助,但是忘记添加 focusNode 让我有点困扰。这是一个例子。

                        TextField(
                                  focusNode: FocusNode(),
                                  textController: _controller,
                                  autoFocus: false,
                                  textStyle: TextStyle(fontSize: 14),
                                  onFieldSubmitted: (text) {},
                                  onChanged: (text) {},
                                  hint: 'Enter the code',
                                  hintColor: CustomColors.mediumGray,
                                  suffixAsset: _voucherController.text.length == 7
                                      ? Assets.ic_approved_voucher
                                      : null,
                                  isIcon: false,
                                  isObscure: false,
                                  maxLength: 7,
                                )
                        

                        closeKeyboard(BuildContext context) {
                            var currentFocus = FocusScope.of(context);
                            if (!currentFocus.hasPrimaryFocus) {
                              currentFocus.unfocus();
                            }
                          }
                        
                            @override
                          Widget build(BuildContext context) {
                            _keyboardVisible = MediaQuery.of(context).viewInsets.bottom != 0;
                            size = MediaQuery.of(context).size;
                            return GestureDetector(
                              onTap: () {
                                closeKeyboard(context);
                              },
                              child: Scaffold(
                                backgroundColor: Colors.white,
                                body: Container(
                                    width: double.maxFinite,
                                    height: double.maxFinite,
                                    child: _buildUI(vm)),
                              ),
                            );
                          }

                        【讨论】:

                          【解决方案22】:

                          我已经为我的基本代码创建了这个函数,到目前为止运行良好!!

                          void hideKeyword(BuildContext context) {
                            FocusScopeNode currentFocus = FocusScope.of(context);
                            if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
                              currentFocus.focusedChild.unfocus();
                            }
                          }
                          

                          【讨论】:

                            【解决方案23】:

                            FocusScope.of(context).unfocus();不工作。

                            此代码适用于 Flutter 2.2.3 版和 null 安全性。

                            WidgetsBinding.instance?.focusManager.primaryFocus?.unfocus()
                            

                            来源:https://github.com/flutter/flutter/issues/20227#issuecomment-512860882

                            例如,将此代码放在 MyAppState 中,以在整个应用程序的外部触摸时应用隐藏键盘。

                            return GestureDetector(
                              onTap: () =>
                                  WidgetsBinding.instance?.focusManager.primaryFocus?.unfocus(),
                              child: MaterialApp(
                                title: 'Flutter Demo',
                                theme: getTheme(),
                                home: _body(),
                              ),
                            );
                            

                            【讨论】:

                              猜你喜欢
                              • 2017-01-15
                              • 2011-08-08
                              • 1970-01-01
                              • 2013-07-03
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多