How to hide soft input keyboard on flutter after clicking outside TextField/anywhere on screen?
FlutterDartKeyboardHideFlutter Problem Overview
Currently, I know the method of hiding the soft keyboard using this code, by onTap
methods of any widget.
FocusScope.of(context).requestFocus(new FocusNode());
But I want to hide the soft keyboard by clicking outside of TextField or anywhere on the screen. Is there any method in flutter
to do this?
Flutter Solutions
Solution 1 - Flutter
You are doing it in the wrong way, just try this simple method to hide the soft keyboard. you just need to wrap your whole screen in the GestureDetector
method and onTap
method write this code.
FocusScope.of(context).requestFocus(new FocusNode());
Here is the complete example:
new Scaffold(
body: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
//rest of your code write here
)
)
Updated (May 2021)
return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
appBar: AppBar(
title: Text('Login'),
),
body: Body(),
),
);
This will work even when you touch the AppBar, new
is optional in Dart 2. FocusManager.instance.primaryFocus
will return the node that currently has the primary focus in the widget tree.
Solution 2 - Flutter
Updated
Starting May 2019, FocusNode
now has unfocus
method:
> Cancels any outstanding requests for focus.
>
> This method is safe to call regardless of whether this node has ever requested focus.
Use unfocus
if you have declared a FocusNode
for your text fields:
final focusNode = FocusNode();
// ...
focusNode.unfocus();
My original answer suggested detach
method - use it only if you need to get rid of your FocusNode
completely. If you plan to keep it around - use unfocus
instead.
If you have not declared a FocusNode
specifically - use unfocus
for the FocusScope
of your current context:
FocusScope.of(context).unfocus();
See revision history for the original answer.
Solution 3 - Flutter
Wrap whole screen in GestureDetector
as
new Scaffold(
body: new GestureDetector(
onTap: () {
// call this method here to hide soft keyboard
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
-
-
-
)
)
Solution 4 - Flutter
I've added this line
behavior: HitTestBehavior.opaque,
to the GestureDetector and it seems to be working now as expected.
@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'),
),
)
);
}
Solution 5 - Flutter
Just as a small side note:
If you use ListView
its keyboardDismissBehavior
property could be of interest:
ListView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
children: [],
)
Solution 6 - Flutter
As of Flutters latest version v1.7.8+hotfix.2, you can hide keyboard using unfocus() instead of requestfocus()
FocusScope.of(context).unfocus()
so whenever you tap in the body part keyboard gets hidden
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Login"),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Container(...)
),
);
}
Solution 7 - Flutter
If you want the behavior to be accessible on any screen in your app, wrap MaterialApp with 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(),
),
);
}
}
Checking hasPrimaryFocus is necessary to prevent Flutter from throwing an exception when trying to unfocus the node at the top of the tree.
(Originally given by James Dixon of the Flutter Igniter blog)
Solution 8 - Flutter
GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
behavior: HitTestBehavior.translucent,
child: rootWidget
)
Solution 9 - Flutter
onPressed: () {
FocusScope.of(context).unfocus();
},
This works for me.
Solution 10 - Flutter
This will work in the latest flutter version.
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(),
),
);
Solution 11 - Flutter
If the focus is inside a webview, keyboard open from another screen or any other then use the below way to hide the keyboard
import 'package:flutter/services.dart';
SystemChannels.textInput.invokeMethod('TextInput.hide');
This worked better than the solution to add FocusScope.of(context).unfocus()
as that solution put me into a loop of the keyboard being shown and hidden
Solution 12 - Flutter
I just developed a small package to give any widget the kind of behavior you are looking for: keyboard_dismisser on pub.dev. You can wrap the whole page with it, so that the keyboard will get dismissed when tapping on any inactive widget.
Solution 13 - Flutter
If you want to do this "the right way", use Listener instead of GestureDetector.
GestureDetector will only work for "single taps", which isn't representative of all possible gestures that can be executed.
Listener(
onPointerDown: (_) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild.unfocus();
}
},
child: MaterialApp(...),
);
Solution 14 - Flutter
Best for me.
I wrap since Material App
because global outside touch
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
}
Resolve below,
I check Platform iOS
only because Android
can dismiss the keyboard the back button.
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(),
...
),
),
So happy your coding.
Flutter version
Solution 15 - Flutter
so easy solution for beginner here is the smoothest solution for you while you need to hide-keyboard when user tap on any area of screen. hope its help you a lot.
Step - 1 : you need to create this method in Global class,
this method wrap you main widget into GestureDetector so when user tap outside the textfield it will hide keyboard automatically
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,
);
}
this method wrap you main widget into Listener so when user touch and scroll up it will hide keyboard automatically
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,
);
}
Step - 2 : here is how to use Global method
@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(),
),
);
}
Solution 16 - Flutter
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
You should check here https://flutterigniter.com/dismiss-keyboard-form-lose-focus/
Solution 17 - Flutter
try this if you are on a stack
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()),
]),
),
),
Solution 18 - Flutter
This will work
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',
Solution 19 - Flutter
It is true what maheshmnj said that from version v1.7.8+hotfix.2, you can hide keyboard using unfocus() instead of requestfocus().
FocusScope.of(context).unfocus()
But in my case I was still presented with a lot of layout errors, as the screen I navigated to was not capable of handling the layout.
════════ 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)
This was handled by inserting "resizeToAvoidBottomInset: false" in the receiving screens Scaffold()
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false, // HERE
appBar: AppBar(
centerTitle: true,
title: Text("Receiving Screen "),
),
body: Container(...)
),
);
}
Solution 20 - Flutter
This is best
Scaffold(
body: GestureDetector(
onTap: () {
if (messageFocusNode.hasFocus) {
messageFocusNode.unfocus();
}
},
child: new Container(
//rest of your code write here
)
)
Solution 21 - Flutter
With Flutter 2.5 GestureDetector.OnTap hasn't worked for me.
Only this worked:
return GestureDetector(
//keyboard pop-down
onTapDown: (_) => FocusManager.instance.primaryFocus?.unfocus(),
behavior: HitTestBehavior.translucent,
child: Scaffold(
Solution 22 - Flutter
UPDATE NOVEMBER 2021
According to the new flutter webview documentation: Putting this piece of code inside the given full example will solve the keyboard dismiss the issue.
@override
void initState() {
super.initState();
// Enable hybrid composition.
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
Full example code:
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',
);
}
}