unite_keyboard_visibility 0.1.2  unite_keyboard_visibility: ^0.1.2 copied to clipboard
unite_keyboard_visibility: ^0.1.2 copied to clipboard
A Flutter plugin to detect keyboard visibility across platforms using modern APIs. Supports floating keyboard and Android 15 predictive back gesture.
[Header]
A Flutter plugin to detect keyboard visibility across platforms using modern APIs. Supports floating keyboard and Android 15 predictive back gesture.
Only Android and iOS are supported at the moment. On iOS, this plugin falls back to an implementation based on flutter_keyboard_visibility until I have time to write my own implementation. Pull requests are welcome.
WASM support is planned.
Desktop platforms like macOS, Windows and Linux are not planned. Still, you are welcome to make contributions in this regard.
| Basic open-close | Predictive back | Floating keyboard | 
|---|---|---|
| [open-close] | [predictive-back] | [floating-keyboard] | 
Installation #
Add the dependency to your pubspec.yaml:
dependencies:
  unite_keyboard_visibility: ^0.1.0
Then get packages:
dart pub get
Usage #
Import and initialize the plugin before accessing visibility:
import 'package:unite_keyboard_visibility/unite_keyboard_visibility.dart';
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await UniteKeyboardVisibility.instance.initialize();
  runApp(const MyApp());
}
On Android, this plugin defines 4 states of keyboard visibility: maybeOpen,
maybeClose, open and close, which corresponds to:
- maybeOpen: The keyboard is moving from- closeto- openor return back to- close.
- maybeClose: The keyboard is moving from- opento- closeor return back to- open.
- close: The keyboard is definitely closed.
- open: The keyboard is definitely opened.
The reason maybeOpen and maybeClose exist is because Android 15 enables
predictive back animation by default, which allows the user to "cancel/reverse"
ongoing keyboard animation. This confuses nearly all visibility detection
methods introduced before Predictive Back in Android 13, which assumed that the
animations/user gestures would not affect the final outcome and thus gave
incorrect or outdated results. While some plugins have been updated to support
this new behavior, more often than not, they try to hide the complexity of
keyboard visibility by using a single isOpen boolean, which is not sufficient
to accurately represent the current keyboard state and leads to awkwardness in
their API usage.
Furthermore, older implementations (before Android 11) rely on outdated APIs that use "bottom inset" to deduce keyboard visibility. This is a flawed approach and was more of a workaround for the problem at the time. Even though it works for basic bottom-aligned keyboards, it falls flat on its face when floating keyboards are involved because now "bottom inset" is always equal to 0, which corresponds to "close" regardless of whether the keyboard is actually closed or not.
This plugin uses modern APIs which hook directly into the underlying native
platform keyboard states and animations (see
here),
allowing you to access exactly at any given time what the current keyboard
visibility is, and whether it is ephemeral (maybeOpen, maybeClose) or stable
(open, close). It does not try to hide the complexity of keyboard visibility
and trusts you to make conscious decisions about how to handle it in your own
app.
On iOS, because the user can't "cancel" the keyboard animation like on Android,
maybeOpen and maybeClose are not needed. Therefore, only open and close
states are emitted on iOS.
To access the current visibility:
final visibility = UniteKeyboardVisibility.instance;
final status = visibility.value;
print('Keyboard is $status');
Listen to visibility changes, the current value will be emited immediately for any new listener:
visibility.valueStream.listen((status) {
  print('Keyboard visibility changed: $status');
});
Plugin lifecycle #
initialize #
Future<void> initialize({
  bool enableLogging = false,
  bool forceFallback = false,
});
Initializes keyboard visibility detection.
- enableLogging: Enables internal logging. May affects performance. Defaults to- false.
- forceFallback: Forces the fallback implementation (flutter_keyboard_visibility) on Android. Have no effect on iOS. Defaults to- false.
Dispose #
Future<void> dispose();
Closes stream and releases all plugin resources.
Troubleshooting #
- Ensure you call initialize()before usingvalueorvalueStream, or aStateErrorwill be thrown when you try to access any plugin resources.
- Use forceFallbackon Android if the native implementation does not detect visibility correctly. This option will be removed once the plugin reaches stable (ideally with full Android, iOS and WASM support).
Contributing #
Contributions are welcome! Please open issues and PRs on GitHub.
License #
MIT