18

Is there any way to get an open keyboard's height in Flutter? I'm trying to pad a bottomSheet widget by the height of the keyboard while it's open.

Alec Sibilia
  • 847
  • 2
  • 10
  • 22

9 Answers9

47

Usually viewInsets provides data about any system ui that obscures the flutter ui. To know about the keyboard height, you can just check for the bottom property of viewInsets, when the keyboard is onscreen, this will hold the height of keyboard else zero.

You can check for the viewInsets with MediaQuery like:

MediaQuery.of(context).viewInsets.bottom

Note: The bottom property may have value even if some other system ui obscures the flutter ui from bottom.

Hope that helps!

Hemanth Raj
  • 32,555
  • 10
  • 92
  • 82
  • 6
    Thanks a lot for the answer, but do you know how to get the keyboard height when the keyboard is not onscreen? I find many native apps can show a container which has the same height of the keyboard in advance when the keyboard is not onscreen. Cheers. – sgon00 May 05 '19 at 16:51
  • @sgon00 yes you are right. did you find how to find the height of the keyboard before its open? – Isuru Bandara May 01 '21 at 06:04
  • @sgon00 Keyboards can change height (even dynamically) depending on the input type, various keyboard configuration options, and keyboard state (emoji mode, etc.), so I don't think there would be an a priori answer, but even if there is, it would depend upon which `TextField` you were planning to type into. – Luke Hutchison Mar 11 '23 at 05:00
  • Note that you have to use `(MediaQuery.of(context).viewInsets.bottom + MediaQuery.of(context).viewPadding.bottom)` to get the keyboard height for the rare devices with a hardware keyboard. Those have a minimized software keyboard with just one line (for accessing the clipboard and similar) which adds only to the viewPadding, but not to the viewInsets. – Konrad May 05 '23 at 14:10
  • Reports 0 for me on Android 11+ – Oliver Dixon May 09 '23 at 11:33
34

The MediaQuery.of(context).viewInsets solution does not work for me. It always says zero even if keyboard is open. Moreover, looking at the highest-upvoted comment in this answer, it is a bad idea to use it as keyboard indicator.

Thus, here is a one-line solution:

final viewInsets = EdgeInsets.fromWindowPadding(WidgetsBinding.instance.window.viewInsets,WidgetsBinding.instance.window.devicePixelRatio);

Then do whatever you want (e.g. viewInsets.bottom is keyboard height) :)


EDIT: https://api.flutter.dev/flutter/dart-ui/FlutterView-class.html is a good source to see how keyboard affects various kinds of padding.

ch271828n
  • 15,854
  • 5
  • 53
  • 88
  • 4
    how can we get keyboard height without opening keyboard. I requirement is related to open a emojis box as overlay of keyboard height which should be same as keyboard height. Any suggestion, please share. Thanks. – Kamlesh Mar 10 '21 at 07:59
  • 1
    @Kamlesh good question, I also want to know it – ch271828n Mar 10 '21 at 12:31
  • 1
    100% This is the solution to use! Other solutions occasionally said 0 when the keyboard was open for me, weirdly unreliable. – BeniaminoBaggins Dec 28 '21 at 05:03
  • 1
    user it as margin or padding like this > margin: EdgeInsets.fromWindowPadding(WidgetsBinding.instance!.window.viewInsets,WidgetsBinding.instance!.window.devicePixelRatio), – Go Goal Mar 28 '22 at 18:47
  • 1
    Does not work on Android 11 or higher for me. – DarkMath May 06 '22 at 15:58
3

In case of complicated widget tree MediaQuery.of(context).viewInsets.bottom gives null even if the keyboard is open. So, we have to mutate values down the tree.

I made the package that provides all needed info down the tree https://pub.dev/packages/flutter_keyboard_size

Welcome to use and in case you find bugs or want to extend functionality please add the issue https://github.com/awaik/flutter_keyboard_size/issues

enter image description here

awaik
  • 10,143
  • 2
  • 44
  • 50
  • Why does a complex widget tree not work with the bottom `viewInsets`? How does propagating this information down work, exactly? – Luke Hutchison Mar 11 '23 at 05:10
  • This was checked last time 2 years ago. I think you can check it again - does it work or not? If to be honest, I don't remember already. – awaik Mar 12 '23 at 09:40
3

This one work for me: https://pub.dev/packages/keyboard_utils

Sample code from package: enter image description here

  • Unfortunately, this does not work for me. I always get an incorrect value which leads to an ugly offset. – DarkMath Mar 13 '22 at 12:33
2

If MediaQuery.of(context).viewInsets.bottom shows 0.0, this should work:

First, go into your Scaffold and set this:

resizeToAvoidBottomInset: false,

THEN you can check the height of the keyboard in this way:

MediaQuery.of(context).viewInsets.bottom,
Matthew Trent
  • 2,611
  • 1
  • 17
  • 30
1

In case you need to get the keyboard height even when the keyboard is not open, you can use the flutter_persistent_keyboard_height package (note: it was created by me).

First thing you need to do is wrap a widget from children of which you want to get the keyboard height with PersistentKeyboardHeightProvider. Wrap your app widget (perhaps MaterialApp) if you want to get keyboard height from all widgets.

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Persistent Keyboard Height Example',
      home: const FlutterPersistentKeyboardHeightExample(),
      builder: (context, child) => PersistentKeyboardHeightProvider(
        child: child!,
      ),
    );
  }
}

And after that you can use the PersistentKeyboardHeight.of(context).keyboardHeight to get the height.

f-person
  • 331
  • 5
  • 16
0

In my case nothing worked, but I needed screen height without keyboard height and LayoutBuilder work perfect.

LayoutBuilder(
  builder: (context, constraints) => Container(
    //maxHeight will change depending on your keyboard visible or not
    height:constraints.maxHeight,
  ),
);

In theory you can do this

LayoutBuilder(
  builder: (context, constraints) {
    double keyboardHeight = MediaQuery.of(context).size.height - constrains.maxHeight;
  }
);
0

You can make your own simple widget that will report when keyboard opened and it's size. Widget itself:

class KeyboardListenerWidget extends StatefulWidget {
  /// {@macro keyboard_listener_widget}
  const KeyboardListenerWidget({required this.phoneSettingsQyreService, required this.keyboardHeight, super.key});

  final IPhoneSettingsQyreService phoneSettingsQyreService;
  final double keyboardHeight;

  @override
  State<KeyboardListenerWidget> createState() => _KeyboardListenerWidgetState();
}

/// State for widget KeyboardListenerWidget
class _KeyboardListenerWidgetState extends State<KeyboardListenerWidget> {
  @override
  void didUpdateWidget(KeyboardListenerWidget oldWidget) {
    super.didUpdateWidget(oldWidget); // Here you report that keyboard state changed
    widget.phoneSettingsQyreService.reportKeyboardOpened(widget.keyboardHeight);
    // Widget configuration changed
  }

  @override
  Widget build(BuildContext context) => const SizedBox.shrink();
}

And IPhoneSettingsQyreService implementation (this service is Singleton, so you create it in the root of your project and pass it to your other widget any way you like):

class PhoneSettingsQyreServiceImpl implements IPhoneSettingsQyreService {
  ///...

  /// Keyboard section:
  final _keyboardHeightStreamController = StreamController<double>.broadcast();
  double _keyboardHeight = 0;

  @override
  double get keyboardHeight => _keyboardHeight;

  @override
  Stream<double> get keyboardHeightStream => _keyboardHeightStreamController.stream;

  @override
  void reportKeyboardOpened(double height) {
    _keyboardHeight = height;
    _keyboardHeightStreamController.add(height);
  }

  @override
  void close() {
    _keyboardHeightStreamController.close();
  }
}

Just add KeyboardListenerWidget to the root of you App like this (widget.child is your Material app with navigator or whatever you are using as the root of your app):

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        KeyboardListenerWidget(
          phoneSettingsQyreService: phoneSettingsService,
          keyboardHeight: MediaQuery.of(context).viewInsets.bottom,
        ),
        widget.child,
        Overlay(key: _overlayKey),
      ],
    );
  }

And just listen keyboardHeightStream in other widgets to rebuild them if it is needed (or use StreamBuilder<double>)

Dmitrii Matunin
  • 275
  • 4
  • 5
0

This answer works, but it's deprecated because of this and this. Here's an updated solution:

final viewInsets = EdgeInsets.fromViewPadding(View.of(context).viewInsets, View.of(context).devicePixelRatio);

You can then use the bottom property to get the keyboard height. The vertical property also works. In a ListView, I put the above as the height of a SizedBox in last element so that I can scroll to the bottom of a ListView while the keyboard is open.

user2233706
  • 6,148
  • 5
  • 44
  • 86