如何关闭屏幕键盘?

How can I dismiss the on screen keyboard?

我正在使用 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());
}

注意:此答案已过时。 .

您可以通过移除 TextFormField 的焦点并将其交给未使用的 FocusNode:

来关闭键盘
FocusScope.of(context).requestFocus(FocusNode());

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

import 'package:flutter/services.dart';

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

它解决了我的问题。

None 以上解决方案对我不起作用。

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

您可以使用 FocusNode class 中的 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());
}

因为在 Flutter 中一切都是小部件,我决定将 FocusScope.of(context).unfocus(); 方法包装在一个简短的实用小部件中。

只需创建 KeyboardHider 小部件:

import 'package:flutter/widgets.dart';

/// A widget that upon tap attempts to hide the keyboard.
class KeyboardHider extends StatelessWidget {
  /// Creates a widget that on tap, hides the keyboard.
  const KeyboardHider({
    required this.child,
    Key? key,
  }) : super(key: key);

  /// The widget below this widget in the tree.
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () => FocusScope.of(context).unfocus(),
      child: child,
    );
  }
}

现在,您可以用 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(),
    );
  }
}

下面的代码帮我隐藏了键盘

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

对于 Flutter 版本 2 或最新版本:

因为 Flutter 2 具有空安全性,这是最好的方法:

FocusManager.instance.primaryFocus?.unfocus();

注意:使用旧方法会导致一些问题,例如保持重建状态;


对于 Flutter 版本 < 2 :

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

FocusScope.of(context).unfocus();

Comment 关于 PR:

Now that #31909 (be75fb3) has landed, you should use FocusScope.of(context).unfocus() instead of FocusScope.of(context).requestFocus(FocusNode()), since FocusNodes are ChangeNotifiers, and should be disposed properly.

-> 不要 使用 ̶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

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

试试这个点击手势

看起来不同的版本有不同的方法。我使用的是 Flutter v1.17.1,以下适用于我。

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

尝试使用 TextEditingController。 一开始,

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

在新闻发布会上,

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

这将关闭键盘。

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

FocusManager.instance.primaryFocus.unfocus();

总而言之,这是适用于 Flutter 1.17 的有效解决方案:

像这样包装您的小部件:

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

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

FocusScope.of(context).unfocus();

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

您还可以为您的文本字段声明一个 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'),
        ),
      ),
    );
  }
}

对我来说,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,
    ...
  ),
)

这样可以简化案例。以下代码仅在键盘打开时才有效

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

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

如果您使用 CustomScrollView,只需输入,

keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,

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

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

如果您的键盘仍然无法关闭,请不要忘记将 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)),
      ),
    );
  }

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

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

FocusScope.of(上下文).unfocus();没用。

此代码适用于 flutter ver 2.2.3 和 null safety。

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

需要时调用此函数

  void hideKeyboard(BuildContext context) {
      FocusScopeNode currentFocus = FocusScope.of(context);
      if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
        FocusManager.instance.primaryFocus?.unfocus();
      }
    }

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

Use SystemChannels.textInput.invokeMethod('TextInput.hide'); will help to close/dismiss the keyboard when the screen loads