在屏幕上单击外部 TextField/anywhere 后,如何在颤动中隐藏软输入键盘?
How to hide soft input keyboard on flutter after clicking outside TextField/anywhere on screen?
目前,我知道使用此代码隐藏软键盘的方法,通过任何小部件的 onTap
方法。
FocusScope.of(context).requestFocus(new FocusNode());
但我想通过单击 TextField 外部或屏幕上的任意位置来隐藏软键盘。 flutter
中有什么方法可以做到这一点吗?
在 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(),
),
);
即使您触摸 AppBar,这也会起作用,new
是 optional in Dart 2。 FocusManager.instance.primaryFocus
将 return 当前在小部件树中具有主要焦点的节点。
我添加了这一行
behavior: HitTestBehavior.opaque,
到 GestureDetector,它现在似乎按预期工作。
@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
方法:
Cancels any outstanding requests for focus.
This method is safe to call regardless of whether this node has ever requested focus.
如果您为文本字段声明了 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最新版本v1.7.8+hotfix.2起,您可以使用unfocus()而不是requestfocus()来隐藏键盘
FocusScope.of(context).unfocus()
因此,只要您点击 body 部分,键盘就会隐藏
@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() 而不是 requestfocus() 来隐藏键盘。
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)
这是通过在接收屏幕中插入“resizeToAvoidBottomInset: false”处理的 Scaffold()
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false, // HERE
appBar: AppBar(
centerTitle: true,
title: Text("Receiving Screen "),
),
body: Container(...)
),
);
}
如果您希望在应用的任何屏幕上都可以访问该行为,请使用 GestureDetector 包裹 MaterialApp:
// 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 提供)
我刚刚开发了一个小程序包,可以为任何小部件提供您正在寻找的行为类型:keyboard_dismisser on pub.dev。你可以用它包裹整个页面,这样当点击任何不活动的小部件时键盘就会消失。
FocusScopeNode currentFocus = FocusScope.of(context);
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(...),
);
这将适用于最新的 flutter 版本。
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(),
...
),
),
很高兴你的编码。
Flutter 版本
这会起作用
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',
如果焦点在 webview 内,键盘从另一个屏幕或任何其他屏幕打开,然后使用以下方式隐藏键盘
import 'package:flutter/services.dart';
SystemChannels.textInput.invokeMethod('TextInput.hide');
这比添加 FocusScope.of(context).unfocus()
的解决方案更有效,因为该解决方案使我进入显示和隐藏键盘的循环
当用户点击屏幕的任何区域时,您需要隐藏键盘时,此处适合初学者的简单解决方案对您来说是最流畅的解决方案。希望对你有很大帮助。
步骤 - 1:您需要在全局 class,
中创建此方法
此方法将您的主要小部件包装到 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,
);
}
此方法将您的主要小部件包装到 Listener 中,因此当用户触摸并向上滚动时它会自动隐藏键盘
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:这里是如何使用全局方法
@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 GestureDetector.OnTap 对我不起作用。
只有这个有效:
return GestureDetector(
//keyboard pop-down
onTapDown: (_) => FocusManager.instance.primaryFocus?.unfocus(),
behavior: HitTestBehavior.translucent,
child: Scaffold(
2021 年 11 月更新
根据新的 flutter webview documentation:
将这段代码放入给定的完整示例中将解决键盘关闭问题。
@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',
);
}
}
目前,我知道使用此代码隐藏软键盘的方法,通过任何小部件的 onTap
方法。
FocusScope.of(context).requestFocus(new FocusNode());
但我想通过单击 TextField 外部或屏幕上的任意位置来隐藏软键盘。 flutter
中有什么方法可以做到这一点吗?
在 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(),
),
);
即使您触摸 AppBar,这也会起作用,new
是 optional in Dart 2。 FocusManager.instance.primaryFocus
将 return 当前在小部件树中具有主要焦点的节点。
我添加了这一行
behavior: HitTestBehavior.opaque,
到 GestureDetector,它现在似乎按预期工作。
@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
方法:
Cancels any outstanding requests for focus.
This method is safe to call regardless of whether this node has ever requested focus.
如果您为文本字段声明了 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最新版本v1.7.8+hotfix.2起,您可以使用unfocus()而不是requestfocus()来隐藏键盘
FocusScope.of(context).unfocus()
因此,只要您点击 body 部分,键盘就会隐藏
@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() 而不是 requestfocus() 来隐藏键盘。
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)
这是通过在接收屏幕中插入“resizeToAvoidBottomInset: false”处理的 Scaffold()
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false, // HERE
appBar: AppBar(
centerTitle: true,
title: Text("Receiving Screen "),
),
body: Container(...)
),
);
}
如果您希望在应用的任何屏幕上都可以访问该行为,请使用 GestureDetector 包裹 MaterialApp:
// 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 提供)
我刚刚开发了一个小程序包,可以为任何小部件提供您正在寻找的行为类型:keyboard_dismisser on pub.dev。你可以用它包裹整个页面,这样当点击任何不活动的小部件时键盘就会消失。
FocusScopeNode currentFocus = FocusScope.of(context);
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(...),
);
这将适用于最新的 flutter 版本。
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(),
...
),
),
很高兴你的编码。
Flutter 版本
这会起作用
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',
如果焦点在 webview 内,键盘从另一个屏幕或任何其他屏幕打开,然后使用以下方式隐藏键盘
import 'package:flutter/services.dart';
SystemChannels.textInput.invokeMethod('TextInput.hide');
这比添加 FocusScope.of(context).unfocus()
的解决方案更有效,因为该解决方案使我进入显示和隐藏键盘的循环
当用户点击屏幕的任何区域时,您需要隐藏键盘时,此处适合初学者的简单解决方案对您来说是最流畅的解决方案。希望对你有很大帮助。
步骤 - 1:您需要在全局 class,
中创建此方法此方法将您的主要小部件包装到 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,
);
}
此方法将您的主要小部件包装到 Listener 中,因此当用户触摸并向上滚动时它会自动隐藏键盘
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:这里是如何使用全局方法
@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 GestureDetector.OnTap 对我不起作用。
只有这个有效:
return GestureDetector(
//keyboard pop-down
onTapDown: (_) => FocusManager.instance.primaryFocus?.unfocus(),
behavior: HitTestBehavior.translucent,
child: Scaffold(
2021 年 11 月更新
根据新的 flutter webview documentation: 将这段代码放入给定的完整示例中将解决键盘关闭问题。
@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',
);
}
}