如何在 Flutter 中点击 TextField 或屏幕上的任何区域后隐藏软键盘?

目前,我知道的方法隐藏软键盘使用这个代码,通过 onTap方法的任何小部件。

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

但是我想通过单击 TextField 外部或屏幕上的任何地方来隐藏软键盘。flutter中有什么方法可以做到这一点吗?

139085 次浏览

GestureDetector中将整个屏幕包装为

new Scaffold(


body: new GestureDetector(
onTap: () {
// call this method here to hide soft keyboard
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
-
-
-
)
)

你的方法不对,试试这个简单的方法来隐藏软键盘。你只需要把你的整个屏幕包装在 GestureDetector方法和 onTap方法编写这段代码。

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

下面是一个完整的例子:

new Scaffold(
body: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
//rest of your code write here
),
),
)

更新(2021年5月)

return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
appBar: AppBar(
title: Text('Login'),
),
body: Body(),
),
);

这将工作,甚至当你触摸应用程序栏,new在 Dart 2中是可选的FocusManager.instance.primaryFocus将返回当前在小部件树中拥有主要焦点的节点。

条件接收安全无效

我加了这一行

behavior: HitTestBehavior.opaque,

手势探测器,现在看起来像预期的那样工作。

 @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).calculatorAdvancedStageTitle),
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Padding(
padding: const EdgeInsets.only(
left: 14,
top: 8,
right: 14,
bottom: 8,
),
child: Text('Work'),
),
)
);
}

更新

从2019年5月开始,FocusNode采用 unfocus方法:

取消任何未完成的焦点请求。

无论此节点是否请求过焦点,调用此方法都是安全的。

如果已经为文本字段声明了 FocusNode,请使用 unfocus:

final focusNode = FocusNode();


// ...


focusNode.unfocus();

我最初的答案建议使用 detach方法-只有当你需要完全摆脱你的 FocusNode时才使用它。如果你打算把它放在身边-使用 unfocus代替。

如果你还没有声明一个 FocusNode-使用 unfocus作为你当前上下文的 FocusScope:

FocusScope.of(context).unfocus();

有关原始答案,请参见修订历史。

GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
behavior: HitTestBehavior.translucent,
child: rootWidget
)

从 Flutters 最新版本1.7.8 + hotfix.2开始,您可以使用 unfocus ()而不是 request focus ()来隐藏键盘

FocusScope.of(context).unfocus()

所以当你点击身体部位时,键盘就会被隐藏起来

  @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Login"),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Container(...)
),
);
}


onPressed: () {
FocusScope.of(context).unfocus();
},

这对我有用。

Maheshmnj 说的没错,在 v1.7.8 + hotfix. 2版本中,可以使用 unfocus ()而不是 request focus ()隐藏键盘。

FocusScope.of(context).unfocus()

但在我的情况下,我仍然面临着许多布局错误,因为我导航到的屏幕不能处理布局。

════════ Exception Caught By rendering library ═════════════════════════════════
The following JsonUnsupportedObjectError was thrown during paint():
Converting object to an encodable object failed: Infinity
When the exception was thrown, this was the stack
#0      _JsonStringifier.writeObject  (dart:convert/json.dart:647:7)
#1      _JsonStringifier.writeMap  (dart:convert/json.dart:728:7)
#2      _JsonStringifier.writeJsonValue  (dart:convert/json.dart:683:21)
#3      _JsonStringifier.writeObject  (dart:convert/json.dart:638:9)
#4      _JsonStringifier.writeList  (dart:convert/json.dart:698:9)

这是通过在接收屏幕中插入“ < em > resizeToAvoidBottomInset: false ”来处理的

@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,   // HERE
appBar: AppBar(
centerTitle: true,
title: Text("Receiving Screen "),
),
body: Container(...)
),
);
}

如果你想在应用程序的任何一个屏幕上都可以访问这个行为,用 GestureDetector 来包装材料应用程序:

// main.dart
import 'package:flutter/material.dart';


void main() => runApp(MyApp());


class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);


if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
),
);
}
}

检查 hasPrimaryFocus 是必要的,以防止当试图取消树顶部节点的焦点时,Flutter 抛出异常。

(原文由 Flutter Igniter 博客的 James Dixon 提供)

我刚刚开发了一个小包,可以为任何小部件提供您正在寻找的行为: Pub.dev 上的键盘 _ 解雇程序。您可以用它包装整个页面,这样当点击任何不活动的小部件时,键盘就会被解除。

FocusScopeNode currentFocus = FocusScope.of (上下文) ;

    if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}

你应该检查这里 https://flutterigniter.com/dismiss-keyboard-form-lose-focus/

作为一个小小的附注:

如果你使用 ListView它的 keyboardDismissBehavior属性可能是有趣的:

ListView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
children: [],
)

如果你在堆栈上,试试这个

body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.transparent,
child: Stack(children: [
_CustomBody(_),
Positioned(
bottom: 15, right: 20, left: 20, child: _BotonNewList()),
]),
),
),

如果您希望以“正确的方式”执行此操作,请使用 Listener 而不是 GestureDetector。

GestureDetector 只适用于“单击”,这并不能代表所有可能执行的手势。

Listener(
onPointerDown: (_) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild.unfocus();
}
},
child: MaterialApp(...),
);

这将工作在最新的颤振版本。

GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);


if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
}
},
child: MaterialApp(
theme: ThemeData.dark().copyWith(
primaryColor: Color(0xFF0A0E21),
scaffoldBackgroundColor: Color(0xFF0A0E21),
),
home: LoginUI(),
),
);

这样最好

Scaffold(
body: GestureDetector(
onTap: () {
if (messageFocusNode.hasFocus) {
messageFocusNode.unfocus();
}
},
child: new Container(
//rest of your code write here
)
)

对我来说是最好的。

我从 Material App开始包装,因为全局外接触

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

下面解决,

我检查平台 iOS只是因为 Android可以取消键盘的 后面的按钮

Listener(
onPointerUp: (_) {
if (Platform.isIOS) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
}
}
},
child: MaterialApp(
debugShowCheckedModeBanner: true,
home: MyHomePage(),
...
),
),

很高兴你能编程。

颤动版

enter image description here

会成功的

 Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return GestureDetector(
onTap: () {
FocusScopeNode focus = FocusScope.of(context);
if (!focus.hasPrimaryFocus && focus.focusedChild != null) {
focus.focusedChild.unfocus();
}
},
child: MaterialApp(
title: 'Flutter Demo',

所以对于初学者来说这是最简单的解决方案,当你需要隐藏键盘时,用户点击屏幕上的任何区域。希望对你有很大帮助。

步骤1: 您需要在 Global 类中创建这个方法,

这个方法将你的主窗口小部件封装到 GestureDetector 中,这样当用户点击文本字段外部时,它会自动隐藏键盘

Widget hideKeyboardWhileTapOnScreen(BuildContext context, {MaterialApp child}){


return GestureDetector(
onTap: () {
if (Platform.isIOS) { //For iOS platform specific condition you can use as per requirement
SystemChannels.textInput.invokeMethod('TextInput.hide');
print("Keyboard Hide");
}
},
child: child,
);
}

这个方法将你的主窗口小部件封装到监听器中,这样当用户触摸和向上滚动时,它会自动隐藏键盘

Widget hideKeyboardWhileTapOnScreen(BuildContext context, {MaterialApp child}){
return Listener(
onPointerUp: (_) {
if (Platform.isIOS) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
print("Call keyboard listner  call");
}
}
},
child: child,
);
}

步骤2: 下面是如何使用 Global 方法

@override
Widget build(BuildContext context) {
 

return hideKeyboardWhileTapOnScreen(context,
child: MaterialApp(
debugShowCheckedModeBanner: false, home: Scaffold(body: setAppbar())),
);
}


Widget setAppbar2() {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.orange),
home: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(),
),
);
}

使用 Flutter 2.5手势检测器 OnTap 对我没用。

只有这个管用:

return GestureDetector(
//keyboard pop-down
onTapDown: (_) => FocusManager.instance.primaryFocus?.unfocus(),
behavior: HitTestBehavior.translucent,
child: Scaffold(

最新情况2021年11月

根据新的颤动网络视图 文件: 将这段代码放在给定的完整示例中将解决键盘忽略这个问题。

@override
void initState() {
super.initState();
// Enable hybrid composition.
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}

完整示例代码:

 import 'dart:io';
import 'package:webview_flutter/webview_flutter.dart';


class WebViewExample extends StatefulWidget {
@override
WebViewExampleState createState() => WebViewExampleState();
}


class WebViewExampleState extends State<WebViewExample> {
@override
void initState() {
super.initState();
// Enable hybrid composition.
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}


@override
Widget build(BuildContext context) {
return WebView(
initialUrl: 'https://flutter.dev',
);
}
}

* 2022年9月更新: : on flutter 3.0.2

如果你有复杂的屏幕,我建议使用 Listener代替。 在这里我要面对一个问题:

在“ GestureDetector”上使用“ HitTestBehavior or.real”捕获事件时存在延迟/延迟?

文件说:

与其侦听原始指针事件,不如考虑侦听 使用 GestureDetector 的高级手势

GestureDetector收听高级手势。我认为这造成了一些延迟或滞后。

我的解决办法:

Listener(
behavior: HitTestBehavior.opaque,
onPointerDown: (_) {
FocusManager.instance.primaryFocus?.unfocus();
},
child: Scaffold()

这将是捕捉事件,当您点击任何地方。

child: Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
labelText: 'User Name', hintText: 'User Name'),
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).requestFocus(_unUsedFocusNode);
},
),
],
),
),

定义焦点节点

FocusNode _unUsedFocusNode = FocusNode();

重写 TextFromField 中的 onTapOut 方法

onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).requestFocus(_unUsedFocusNode);
},

编辑:

Note: it will work in sdk Flutter 3.6.0-0.1.pre Dart SDK 2.19.0-374.1.beta