Collin Jackson
Collin Jackson

Reputation: 116828

How can I dismiss the on screen keyboard?

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

Answers (30)

Ritika Bansal
Ritika Bansal

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

Pascal
Pascal

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 of FocusScope.of(context).requestFocus(FocusNode()), since FocusNodes are ChangeNotifiers, 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

codrikaz
codrikaz

Reputation: 293

Two ways, but needed both

  1. Wrap the Scaffold with GestureDetector or InkWell

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

  1. If you want to scroll the list of data, or simple scroll then define this

keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,

Upvotes: 0

jbryanh
jbryanh

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

Jackie Z
Jackie Z

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

anand
anand

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

Mohamed
Mohamed

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

omega_mi
omega_mi

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

Lokendra singh Chauhan
Lokendra singh Chauhan

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

ynn
ynn

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

Yasin Ege
Yasin Ege

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

Ayush Sth
Ayush Sth

Reputation: 332

add this code inside build widget

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

Upvotes: 4

Supun Sandaruwan
Supun Sandaruwan

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

Hari
Hari

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

Masum Billah Sanjid
Masum Billah Sanjid

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

Vince Varga
Vince Varga

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

Quyen Anh Nguyen
Quyen Anh Nguyen

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

wilfredonoyola
wilfredonoyola

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

CHANDUKA SAMARASINGHE.
CHANDUKA SAMARASINGHE.

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

Aykut Acikgoz
Aykut Acikgoz

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

9Dragons
9Dragons

Reputation: 165

if you use CustomScrollView, just put,

keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,

Upvotes: 8

AH Developer
AH Developer

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

Vamsi Krishna
Vamsi Krishna

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

Ilya Iksent
Ilya Iksent

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

Gagan Yadav
Gagan Yadav

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

Cassio Seffrin
Cassio Seffrin

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

Valentin Seehausen
Valentin Seehausen

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

suztomo
suztomo

Reputation: 5202

For Flutter 1.17.3 (stable channel as of June 2020), use

FocusManager.instance.primaryFocus.unfocus();

Upvotes: 107

dbyuvaraj
dbyuvaraj

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

Collin Jackson
Collin Jackson

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

Related Questions