Reputation: 116828
I am collecting user input with a TextFormField
and when the user presses a FloatingActionButton
indicating they are done, I want to dismiss the on screen keyboard.
How do I make the keyboard go away automatically?
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());
}
Upvotes: 525
Views: 412949
Reputation: 101
Just wrap your scaffold with Gesture Detector as shown below to dismiss the keyboard:
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(),
);
Upvotes: 1
Reputation: 16651
For Flutter version 2 or later :
Since Flutter 2
with null safety this is the best way:
FocusManager.instance.primaryFocus?.unfocus();
Note: using old ways leads to some problems like keep rebuild states;
For Flutter version < 2 :
As of Flutter v1.7.8+hotfix.2, the way to go is:
FocusScope.of(context).unfocus();
Comment on PR about that:
Now that #31909 (be75fb3) has landed, you should use
FocusScope.of(context).unfocus()
instead ofFocusScope.of(context).requestFocus(FocusNode())
, sinceFocusNode
s areChangeNotifiers
, and should be disposed properly.
-> DO NOT use ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶
anymore.
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̶(̶)̶)̶;̶
Read more about the FocusScope
class in the flutter docs.
Upvotes: 969
Reputation: 293
Two ways, but needed both
GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: Scaffold(....) );
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
Upvotes: 0
Reputation: 2033
The easiest way to do this is with the onTapOutside method that TextField provides:
onTapOutside: (PointerDownEvent event) {
FocusManager.instance.primaryFocus?.unfocus();
},
Upvotes: 29
Reputation: 19
I think there is a easy way.
set keyboardType: TextInputType.none,
TextField( autofocus: true, keyboardType: TextInputType.none,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: '',
),
controller: _controller,
)
Upvotes: -1
Reputation: 111
First Connect the TextField with focusNode
TextField(
focusNode: focusNode),
now for show/open the keyboard call
focusNode.requestFocus();
and for hide/dismiss keyboard call
focusNode.unfocus();
and if you want to know keyboard is visible or not at that time check the belew condition
final keyBoardVisible = MediaQuery.of(context).viewInsets.bottom != 0;
here keyBoardVisible value is true if keyboard is visible and false for dismissed keyboard
Upvotes: 2
Reputation: 123
To dismiss keyboard when TextField or some widget loses focus you can do this:
TextField(
onTapOutside: (event) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
},
);
Upvotes: 11
Reputation: 718
In flutter 3.7.2 worked, wrap you Scaffold inside GestureDetector to dismiss keyboard when tap somewhere outside.
GestureDetector(
onTap: () {
SystemChannels.textInput.invokeMethod<void>('TextInput.hide');
},
child: Scaffold(),
),
Upvotes: 10
Reputation: 161
You can use this:
FocusScope.of(context).requestFocus(FocusNode());
And you can use this onTap
of GestureDetector
or InkWell
like this:
GestureDetector(
onTap: () {
// THIS FOCUS SCOPE WILL CLOSE THE KEYBOARD
FocusScope.of(context).requestFocus(FocusNode());
forgotPasswordAPI(emailController.text);
},
}
Upvotes: 4
Reputation: 4857
If you use TextField(maxLines: null)
and just want to show Done
button ON the screen keyboard to hide it, the code below works.
TextField(
keyboardType: TextInputType.text,
maxLines: null,
)
Side note: why in the first place doesn't the keyboard show Done
button? The reason is found in the implementation of TextField
:
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
Upvotes: -2
Reputation: 723
If your keyboard still won't turn off , don't forget add focusNode to TextField. The above information was helpful, but forgetting to add focusNode bothered me a bit. Here an example.
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)),
),
);
}
Upvotes: 3
Reputation: 332
add this code inside build widget
FocusScope.of(context).requestFocus(FocusNode());
Upvotes: 4
Reputation: 2418
====== Dismiss the keyboard after clicking out of the TextField =======
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(), //this will dismiss keyboard
child: Scaffold(
body: SafeArea(
.........
====== Dismiss the keyboard when scrolling the screen =======
ListView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, //this will dismiss
children: [
..........
The SingleChildScrollView widget also have this property.
Upvotes: 5
Reputation: 137
Use SystemChannels.textInput.invokeMethod('TextInput.hide');
. It will close/dismiss the keyboard when the screen loads.
void initState() {
super.initState();
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
Upvotes: 3
Reputation: 1189
Call this function when you needed
void hideKeyboard(BuildContext context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
Upvotes: 6
Reputation: 6968
As in Flutter everything is a widget, I decided to wrap the FocusScope.of(context).unfocus();
approach in a short utility widget.
Just create the KeyboardHider
widget:
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,
);
}
}
Now, you can wrap any widget (very convenient when using a good IDE) with the KeyboardHider
widget, and then when you tap on something, the keyboard will close automatically. It works well with forms and other tappable areas.
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(),
);
}
}
Upvotes: 25
Reputation: 1780
FocusScope.of(context).unfocus(); doesn't work.
This code works for me at flutter ver 2.2.3 and null safety.
WidgetsBinding.instance?.focusManager.primaryFocus?.unfocus()
Source: https://github.com/flutter/flutter/issues/20227#issuecomment-512860882
For example, put this code in MyAppState to apply hide keyboard when touch outside for whole app.
return GestureDetector(
onTap: () =>
WidgetsBinding.instance?.focusManager.primaryFocus?.unfocus(),
child: MaterialApp(
title: 'Flutter Demo',
theme: getTheme(),
home: _body(),
),
);
Upvotes: 2
Reputation: 515
I have created this function to my base code, so far works well!!
void hideKeyword(BuildContext context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
}
Upvotes: 2
Reputation: 422
try using a TextEditingController. at the begining,
final myController = TextEditingController();
@override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
and in the on press event,
onPressed: () {
myController.clear();}
this will dismiss the keybord.
Upvotes: -1
Reputation: 115
You can wrap your widget with "GestureDetector", then assign "FocusScope.of(context).unfocus()" to its onTap function
GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: child,
);
Upvotes: 6
Reputation: 165
if you use CustomScrollView, just put,
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
Upvotes: 8
Reputation: 51
FocusScope.of(context).unfocus() has a downside when using with filtered listView. Apart from so many details and concisely, use keyboard_dismisser package in https://pub.dev/packages/keyboard_dismisser will solve all the problems.
Upvotes: 1
Reputation: 363
This may simplify the case. Below code will work only if keyboard is open
if(FocusScope.of(context).isFirstFocus) {
FocusScope.of(context).requestFocus(new FocusNode());
}
Upvotes: 19
Reputation: 1798
For me, the Listener above App widget is the best approach I've found:
Listener(
onPointerUp: (_) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
},
child: MaterialApp(
title: 'Flutter Test App',
theme: theme,
...
),
)
Upvotes: 21
Reputation: 141
You can also declare a focusNode for you textfield and when you are done you can just call the unfocus method on that focusNode and also dispose it
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'),
),
),
);
}
}
Upvotes: 2
Reputation: 8600
To dismiss the keyboard (1.7.8+hotfix.2 and above) just call the method below:
FocusScope.of(context).unfocus();
Once the FocusScope.of(context).unfocus() method already check if there is focus before dismiss the keyboard it's not needed to check it. But in case you need it just call another context method: FocusScope.of(context).hasPrimaryFocus
Upvotes: 33
Reputation: 755
To summarize, this is a working solution for Flutter 1.17:
Wrap your Widget like this:
GestureDetector(
onTap: FocusScope.of(context).unfocus,
child: YourWidget(),
);
Upvotes: 8
Reputation: 5202
For Flutter 1.17.3 (stable channel as of June 2020), use
FocusManager.instance.primaryFocus.unfocus();
Upvotes: 107
Reputation: 505
Looks like different approaches for different version. I am using Flutter v1.17.1 and the below works for me.
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
}
Upvotes: 29
Reputation: 116828
Note: This answer is outdated. See the answer for newer versions of Flutter.
You can dismiss the keyboard by taking away the focus of the TextFormField
and giving it to an unused FocusNode
:
FocusScope.of(context).requestFocus(FocusNode());
Upvotes: 342