Flutter: Detect keyboard open and close
DartFlutterDart Problem Overview
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
:-)
Dart Solutions
Solution 1 - Dart
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
Solution 2 - Dart
I just created a Flutter plugin to notify about keyboard open and close events. It works both on Android and iOS.
import 'package:keyboard_visibility/keyboard_visibility.dart';
@override
void initState() {
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible) {
print(visible);
},
);
}
Solution 3 - Dart
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.
}
Solution 4 - Dart
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.
Solution 5 - Dart
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;
}
Solution 6 - Dart
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;
Solution 7 - Dart
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);
}
}
Solution 8 - Dart
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'}',
);
}
);
Solution 9 - Dart
With Flutter 2.0 and null safety, I use this package - it has no streams, pure Dart, gives additional information about keyboard height, etc.
Solution 10 - Dart
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.
Solution 11 - Dart
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()"),
),