如何关闭屏幕键盘?


137

我正在收集带有a的用户输入,TextFormField并且当用户按a 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());
}

Collin,@ Pascal的第二个答案应该是更新的,更正的答案。
杰克

Answers:


223

从Flutter v1.7.8 + hotfix.2开始,方法是:

FocusScope.of(context).unfocus()

评论 PR:

现在#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̶(̶)̶)̶;̶

1
为我工作了hotfix v1.7.8 + hotfix.4
Rajesh Jr.

2
为我工作,此答案应掩盖为正确的答案
user3087360

@kine您能详细说明吗?每一个文件,这是做的(见的方式api.flutter.dev/flutter/widgets/FocusNode/unfocus.html
帕斯卡尔

@Pascal是的,我已经阅读了文档,这将是我的首选解决方案,但是在我的应用程序中,它并不总是有效(这是一个非常复杂的表格,带有多个TextFields和其他编辑小部件)。我不知道为什么,但有时unfocus没有任何效果。将其替换为可接受的解决方案(无其他更改)可解决此问题。可能与unfocus调用位置有关。我需要调用它,例如,CheckBoxListTile.onChanged当用户与复选框小部件进行交互时,从关闭键盘,以及从其他类似位置调用它。我不记得确切的问题位置。
kine

@kine感谢您的解释。为Flutter团队提供一个例子将是令人惊讶的;-)
Pascal

206

注意:此答案已过时。查看最新版本的Flutter的答案

您可以通过移开键盘的焦点TextFormField并将其分配给未使用的键盘来关闭键盘FocusNode

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

您将在哪里实现此代码?在TextFormField中;也许是在onChanged:您自定义按钮之后或正在执行?
小查尔斯(Charles Jr)

@CharlesJr我通过按钮的操作来做到这一点。
Duncan Jones

您可以根据需要使用我的包:) pub.dartlang.org/packages/keyboard_actions
diegoveloper

17
这是Flutter v1.7.8之前的版本-请参阅答案stackoverflow.com/a/56946311/8696915,其中给出了FocusScope.of(context).unfocus()
理查德·约翰逊

1
如果您可以访问.unfocus(),请不要执行此操作,因为它会导致内存泄漏。新的FocusNode()将永远不会被清除。请参阅有关.unfocus()的评论
Michael Peterson

70

FocusScope解决方案对我不起作用。我发现了另一个:

import 'package:flutter/services.dart';

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

它解决了我的问题。


调用它不会为我隐藏键盘。它应该同时在Android和iOS上运行吗?
贾多

在iOS(12.1,iPhone 5s)和Android(像素3)上为我工作
Jannie Theunissen,

你把它放在哪里?我尝试将其添加为应用程序中的第一部分代码,但它没有执行任何操作。
Justin808 '19

您是什么意思-“第一部分代码”?build例如,将其插入方法。
安德烈·图尔科夫斯基

1
数字键盘有与此等效的功能吗?
Daniel Maksimovich

19

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

FocusManager.instance.primaryFocus.unfocus();

12

以上所有解决方案都不适合我。

Flutter建议这样做-将小部件放在新的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;
}}

12

以下代码帮助我隐藏了键盘

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


8
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'),
    ),
  ), })

轻按手势尝试一下


谢谢...采用此解决方案
Ajay Kumar

6

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

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

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

4

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

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());
}

1
嗨!最好是您可以编辑答案以在答案中添加更多上下文。
凹槽复数

1
最少编码量的最佳解决方案
Val

是的,如果点击特定的窗口小部件,它将消除焦点。无法将其添加到我的应用程序的每个小部件中。
Dpedrinha

点击小部件仅仅是调用unfocus方法的一种方式。如果您不想在您的应用程序上发送垃圾邮件,则可以使用其他方法,例如TextFormField更改事件或响应模式,这取决于您应用程序的体系结构。
Evandro Ap。S.19年

4

对于不同的版本,似乎采用不同的方法。我正在使用Flutter v1.17.1,以下对我有用。

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

1
_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>[/*...*/],
    ),
    ),
 );
}

0

尝试使用文本编辑控制器。一开始

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

在新闻发布会上

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

这将关闭键盘。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.