96

I have a BottomNavigationBar at the upper-most level of my application. I want to detect keyboard open and close basically anywhere in the app/subtree, so I can show and hide the BottomNavigationBar whenever the keyboard is visible.

This is a general issue and may not be directly related to the BottomNavigationBar. In other words, abstract from the BottomNavigationBar :-)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jakob Kristensen
  • 1,647
  • 3
  • 12
  • 22

11 Answers11

107

To check for keyboard visibility, just check for the viewInsets property anywhere in the widget tree. The keyboard is hidden when viewInsets.bottom is equal to zero.

You can check for the viewInsets with MediaQuery like:

MediaQuery.of(context).viewInsets.bottom
Francesco - FL
  • 603
  • 1
  • 4
  • 25
Hemanth Raj
  • 32,555
  • 10
  • 92
  • 82
  • 55
    That's a bad practice. ViewInset is not specific to keyboard. I'd suggest to use platform_channel to directly call native API that tells if the keyboard is visible or not. – Rémi Rousselet Feb 12 '18 at 20:50
  • 1
    @Darky But that is the only way you can do it. Observe window size to infer if keyboard is visible, there is no direct method as far as I know. You can take a look at [this](https://stackoverflow.com/questions/4745988/how-do-i-detect-if-software-keyboard-is-visible-on-android-device). If I'm wrong do correct me. – Hemanth Raj Feb 13 '18 at 06:33
  • And more over I thought implementing a platform_channel is unnecessary here as the `viewInsets` are already being updated with respect to events. – Hemanth Raj Feb 13 '18 at 06:36
  • 6
    But ViewInset is not "isKeyboardVisible". If you have a floating keyboard, it'll be visible with a ViewInset of 0 for example – Rémi Rousselet Feb 13 '18 at 10:34
  • 1
    That's true, but ideally `isKeyboardVisible` = viewInsets.bottom > 200px or not equal to zero ideally. There no other way that you can tell if keyboard is visible. – Hemanth Raj Feb 13 '18 at 10:36
  • I think floating keyboard scenario is inevitable. I find no docs or reference to detect a floating keyboard. If can, do educate me. :) – Hemanth Raj Feb 13 '18 at 10:40
  • Platform_channel should make things slightly better. IOS (and most likely fushia) have some events on keyboard visibility. The problem is Android I guess. But then for Android only you could use ViewInset. – Rémi Rousselet Feb 13 '18 at 10:46
  • 3
    Implementing the **WidgetsBindingObserver** and in particular the method *didChangeMetrics* may be a solution. See [article](https://www.didierboelens.com/2018/04/hint-4-ensure-a-textfield-or-textformfield-is-visible-in-the-viewport-when-has-the-focus/) – boeledi Apr 28 '18 at 02:40
  • 1
    This works pretty well, and I'm only really using it because my page layout looks bad when it's scrunched to such a small space so I remove some things. So I don't think this is a a bad solution for most cases (which pertain to UI). – csga5000 Jun 05 '18 at 16:16
  • This is the only best solution I think.... @RémiRousselet If we know the use cases, using this solution is not at all an issue.... – Yesudass Moses Apr 24 '20 at 20:37
  • Bad solution, there is a pure Dart implementation below using WidgetsBindingObserver – Kohls Nov 30 '21 at 20:56
  • Are you aware that the MediaQuery.of is already subscribed to WidgetsBinding window changes. And it does the same. Would be happy to hear why you think it's bad solution? And WidgetsBindingObserver is also not pure Dart implementation I suppose, it depends on flutter/foundation AFAIK. – Hemanth Raj Dec 02 '21 at 15:28
  • 1
    In most cases, when there is a floating keyboard, you would like to treat it as no keyboard, anyway! Such as in the example given in the qn... with the bottom bar... Why hide the bottom bar when a floating keyboard appears?! ‍♀️ (There may be use cases where you would still like to know, though, I guess. But they gotta be few!) – Karolina Hagegård Aug 26 '22 at 14:05
56

I just created a Flutter plugin to notify about keyboard open and close events. It works both on Android and iOS.

keyboard_visibility


import 'package:keyboard_visibility/keyboard_visibility.dart';

@override
void initState() {
  super.initState();

  KeyboardVisibilityNotification().addNewListener(
    onChange: (bool visible) {
      print(visible);
    },
  );
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ad ee
  • 577
  • 4
  • 2
  • 1
    how are we suppossed to use this plugin? any documentation? – Jose Jet Jan 04 '19 at 12:17
  • 1
    Just refer to the read me. It is quite simple to use: [link](https://pub.dartlang.org/packages/keyboard_visibility#-readme-tab-) – ad ee Jan 06 '19 at 21:33
  • Sorry I could not find the package on pub.dartlang. This is brilliant, the only way that I found to know if the keyboard is really visible or not (even if your keyboard has a floating keyboard) – Jose Jet Jan 07 '19 at 08:03
  • Here the link to the dartlang page: [link](https://pub.dartlang.org/packages/keyboard_visibility) – ad ee Jan 08 '19 at 09:24
  • 13
    Plugin is not updated, go to this fork instead: https://github.com/MisterJimson/flutter_keyboard_visibility – MatPag May 09 '20 at 10:11
  • I did like you said and it throws this: The following MissingPluginException was thrown while activating platform stream on channel github.com/adee42/flutter_keyboard_visibility: MissingPluginException(No implementation found for method listen on channel github.com/adee42/flutter_keyboard_visibility) – Hyung Tae Carapeto Figur Jul 18 '20 at 04:59
  • This plugin will prevent you doing build for release – Tyrone Chris Abad Nov 09 '20 at 03:19
  • Not working and getting error - MissingPluginException(No implementation found for method listen on channel github.com/adee42/flutter_keyboard_visibility) – Kamlesh Jan 31 '21 at 16:05
  • 5
    This package does not support NULL SEFETY, thats why it is USELESS. – Kamlesh Sep 06 '21 at 07:54
  • 1
    @Kamlesh that's a flag for me to you, it can still be usefull to some and the caps-lock writing is absolutely unnecesseary – MwBakker May 09 '22 at 09:23
  • If you are plugin author, take a look at the docs for migrating the plugin to the V2 embedding: https://flutter.dev/go/android-plugin-migration. – kahan x10 Sep 20 '22 at 12:00
  • use this. https://pub.dev/packages/flutter_keyboard_visibility. – Vipin Krishna Oct 12 '22 at 17:13
36

You can use WidgetsBinding.instance.window.viewInsets.bottom. If its value is greater than 0.0 then the keyboard is visible.

    if(WidgetsBinding.instance.window.viewInsets.bottom > 0.0)
    {
       // Keyboard is visible.
    }
    else
    {
       // Keyboard is not visible.
    }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
deepak raj
  • 3,331
  • 1
  • 12
  • 20
27

You can use the keyboard_visibility package to do this effectively. I've used it, and it works like a charm.

To install

dependencies:
  keyboard_visibility: ^0.5.2

Usage

import 'package:keyboard_visibility/keyboard_visibility.dart';

@protected
void initState() {
  super.initState();

  KeyboardVisibilityNotification().addNewListener(
    onChange: (bool visible) {
      print(visible);
    },
  );
}

It also supports listeners like show/hide.

Here is the link.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
26

In your StatefullWidget, create a variable:

bool _keyboardVisible = false;

Then initialize that variable in the build widget;

@override
Widget build(BuildContext context) {
    _keyboardVisible = MediaQuery.of(context).viewInsets.bottom != 0;
    return child;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abdurahman Popal
  • 2,859
  • 24
  • 18
11

This is my solution, which uses WidgetsBindingObserver to observe window size changes, and determine whether the keyboard is hidden based on this.

/// My widget state,it can remove the focus to end editing when the keyboard is hidden.
class MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
  /// Determine whether the keyboard is hidden.
  Future<bool> get keyboardHidden async {
    // If the embedded value at the bottom of the window is not greater than 0, the keyboard is not displayed.
    final check = () => (WidgetsBinding.instance?.window.viewInsets.bottom ?? 0) <= 0;
    // If the keyboard is displayed, return the result directly.
    if (!check()) return false;
    // If the keyboard is hidden, in order to cope with the misjudgment caused by the keyboard display/hidden animation process, wait for 0.1 seconds and then check again and return the result.
    return await Future.delayed(Duration(milliseconds: 100), () => check());
  }

  @override
  void initState() {
    super.initState();
    // Used to obtain the change of the window size to determine whether the keyboard is hidden.
    WidgetsBinding.instance?.addObserver(this);
  }

  @override
  void dispose() {
    // stop Observing the window size changes.
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }
  
  @override
  void didChangeMetrics() {
    // When the window insets changes, the method will be called by the system, where we can judge whether the keyboard is hidden.
    // If the keyboard is hidden, unfocus to end editing.
    keyboardHidden.then((value) => value ? FocusManager.instance.primaryFocus?.unfocus() : null);
  }
}
jqgsninimo
  • 6,562
  • 1
  • 36
  • 30
8

You can use Flutter keyboard visibility plugin

@override
Widget build(BuildContext context) {
  return KeyboardVisibilityBuilder(
    builder: (context, isKeyboardVisible) {
      return Text(
        'The keyboard is: ${isKeyboardVisible ? 'VISIBLE' : 'NOT VISIBLE'}',
      );
    }
  );
Gustavo Lopes
  • 3,794
  • 4
  • 17
  • 57
M.AQIB
  • 359
  • 5
  • 11
7

You can use MediaQuery.of(context).viewInsets.bottom. Just look at the documentation below.

/// The parts of the display that are completely obscured by system UI, /// typically by the device's keyboard. /// /// When a mobile device's keyboard is visible viewInsets.bottom /// corresponds to the top of the keyboard. /// /// This value is independent of the [padding]: both values are /// measured from the edges of the [MediaQuery] widget's bounds. The /// bounds of the top level MediaQuery created by [WidgetsApp] are the /// same as the window (often the mobile device screen) that contains the app. ///
/// See also: /// /// * [MediaQueryData], which provides some additional detail about this /// property and how it differs from [padding]. final EdgeInsets viewInsets;

2

With Flutter 2.0 and null safety, I use this package - it has no streams, pure Dart, gives additional information about keyboard height, etc.

flutter_keyboard_size 1.0.0+4

Enter image description here

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
awaik
  • 10,143
  • 2
  • 44
  • 50
1

I used a workaround. I added a focusNode to the input and added a listener to that.

See the implementation here add focus listener to input.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-2

I found an easier solution here:

Put the DesiredBottomWidget in a Stack() with a Positioned(top: somevalue), and it will be hidden when the keyboard appears.

Example:

Stack(
    "Somewidget()",
    Positioned(
        top: "somevalue",
        child: "DesiredBottomWidget()"),
),
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131