### Using Keyboard Detection Controller in Build Method Source: https://github.com/lamnhan066/keyboard_detection/blob/main/README.md Utilize the KeyboardDetectionController within the build method to display the current keyboard state and keyboard size once it's loaded. Includes navigation examples. ```dart KeyboardDetection( controller: keyboardDetectionController, child: Scaffold( appBar: AppBar( title: const Text('Keyboard Detection'), ), body: Center( child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('State: ${keyboardDetectionController.state}'), FutureBuilder( future: keyboardDetectionController.ensureSizeLoaded, builder: (context, snapshot) { if (snapshot.hasData) { return Text('Keyboard size loaded: ${keyboardDetectionController.size}'); } return const Text('Loading keyboard size...'); }, ), const TextField(), ElevatedButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (_) => const MyApp()), ); }, child: const Text('Navigate to another page'), ), ElevatedButton( onPressed: () { Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (_) => const MyApp(), ), (_) => false, ); }, child: const Text('Move to another page'), ), ], ), ), ), ), ); ``` -------------------------------- ### Advanced Keyboard Detection Controller Setup Source: https://github.com/lamnhan066/keyboard_detection/blob/main/README.md Declare KeyboardDetectionController outside the build method for more control. This includes setting up callbacks for state changes, listening to streams, and adding one-time or looped callbacks. ```dart late KeyboardDetectionController keyboardDetectionController; @override void initState() { keyboardDetectionController = KeyboardDetectionController( onChanged: (value) { print('Keyboard visibility changed: $value'); keyboardState = value; }, ); // Listen to the stream _sub = keyboardDetectionController.stream.listen((state) { print('Stream update: $state'); }); // Add one-time callback keyboardDetectionController.addCallback((state) { print('One-time callback: $state'); return false; }); // Add looped callback keyboardDetectionController.addCallback((state) { print('Looped callback: $state'); return true; }); // Add looped future callback keyboardDetectionController.addCallback((state) async { await Future.delayed(const Duration(milliseconds: 100)); print('Looped future callback: $state'); return true; }); super.initState(); } ``` -------------------------------- ### controller.stateAsBool() Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Gets the keyboard visibility as a nullable boolean. The `includeTransitionalState` parameter determines if transitional states like 'visibling' and 'hiding' are considered visible or hidden. ```APIDOC ## controller.stateAsBool([bool includeTransitionalState = false]) ### Description Collapses the five-value enum `KeyboardState` to a nullable boolean. `null` indicates an unknown state, `true` indicates the keyboard is visible (or showing if `includeTransitionalState` is true), and `false` indicates the keyboard is hidden (or hiding). ### Parameters - **includeTransitionalState** (bool) - Optional - If true, transitional states (`visibling`/`hiding`) are included in the boolean result. ### Returns - `bool?`: A nullable boolean representing keyboard visibility. ``` -------------------------------- ### Handle KeyboardState Enum Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use the KeyboardState enum to distinguish between animated transition phases and stable terminal phases of the keyboard lifecycle. This allows for immediate responses to animation starts. ```dart import 'package:keyboard_detection/keyboard_detection.dart'; void handleKeyboardState(KeyboardState state) { switch (state) { case KeyboardState.unknown: // Plugin just initialised; no measurement yet. break; case KeyboardState.visibling: // Keyboard is animating INTO view — inset is increasing. // Useful for starting your own slide-up animation in sync. break; case KeyboardState.visible: // Keyboard is fully open and stable. break; case KeyboardState.hiding: // Keyboard is animating OUT OF view — inset is decreasing. break; case KeyboardState.hidden: // Keyboard is fully dismissed. break; } } ``` -------------------------------- ### Get Keyboard Visibility as Boolean Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use `controller.stateAsBool()` to collapse the keyboard state enum into a nullable boolean. The `includeTransitionalState` parameter determines if states like `visibling` and `hiding` are included. ```dart // Without includeTransitionalState (default false): // true → KeyboardState.visible only // false → KeyboardState.hidden only // null → KeyboardState.unknown final bool? stable = controller.stateAsBool(); // With includeTransitionalState = true: // true → KeyboardState.visible OR KeyboardState.visibling // false → KeyboardState.hidden OR KeyboardState.hiding // null → KeyboardState.unknown final bool? withTransition = controller.stateAsBool(true); // Practical example — adjust bottom padding reactively Padding( padding: EdgeInsets.only( bottom: controller.stateAsBool(true) == true ? 0 : 16, ), child: const SubmitButton(), ) ``` -------------------------------- ### Read Keyboard State Synchronously Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use `controller.state` to get the last known keyboard state without triggering new observations. This is safe to call from anywhere, including within the `build` method. ```dart class KeyboardAwareButton extends StatelessWidget { final KeyboardDetectionController controller; const KeyboardAwareButton({super.key, required this.controller}); @override Widget build(BuildContext context) { // Conditionally render based on current keyboard state final isKeyboardVisible = controller.state == KeyboardState.visible; return Visibility( visible: !isKeyboardVisible, child: FloatingActionButton( onPressed: () {}, child: const Icon(Icons.add), ), ); } } ``` -------------------------------- ### Asynchronous Keyboard Size Loading Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt An asynchronous method to wait for the keyboard size to be measured for the first time, suitable for use with `FutureBuilder`. ```APIDOC ## `controller.ensureSizeLoaded` — Await keyboard size asynchronously `ensureSizeLoaded` is a `Future` that completes once the keyboard height has been measured for the first time. It is ideal for use with `FutureBuilder` to defer UI that depends on the keyboard dimensions without blocking the render. ```dart FutureBuilder( future: _controller.ensureSizeLoaded, builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done) { // Size is now available return Text( 'Keyboard size: ${_controller.size.toStringAsFixed(1)} logical px', style: const TextStyle(fontWeight: FontWeight.bold), ); } // Still waiting for the first keyboard appearance return const Row( children: [ SizedBox( width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2), ), SizedBox(width: 8), Text('Waiting for keyboard size...'), ], ); }, ) ``` ``` -------------------------------- ### Create KeyboardDetectionController Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Instantiate KeyboardDetectionController to manage keyboard state. The optional onChanged callback is the simplest way to react to state transitions. A silent controller can be used if only stream or other callbacks are needed. ```dart // Minimal constructor — only onChanged is required final controller = KeyboardDetectionController( onChanged: (KeyboardState state) { // Called every time state transitions: // unknown → visibling → visible → hiding → hidden → … debugPrint('Keyboard state: $state'); }, ); // No-callback variant — useful when you only need stream or callbacks final silentController = KeyboardDetectionController(); ``` -------------------------------- ### Await Keyboard Size Asynchronously Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use `controller.ensureSizeLoaded` (a `Future`) to asynchronously wait for the first stable keyboard measurement. This is ideal for `FutureBuilder` to defer UI elements dependent on keyboard dimensions. ```dart FutureBuilder( future: _controller.ensureSizeLoaded, builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done) { // Size is now available return Text( 'Keyboard size: ${_controller.size.toStringAsFixed(1)} logical px', style: const TextStyle(fontWeight: FontWeight.bold), ); } // Still waiting for the first keyboard appearance return const Row( children: [ SizedBox( width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2), ), SizedBox(width: 8), Text('Waiting for keyboard size...'), ], ); }, ) ``` -------------------------------- ### Callback Management Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Methods for registering and unregistering callbacks to listen for keyboard state changes. You can remove specific callbacks or clear all of them. ```APIDOC ## `controller.unregisterCallback()` / `unregisterAllCallbacks()` — Remove callbacks explicitly Use `unregisterCallback` to remove a specific previously-registered callback by reference, or `unregisterAllCallbacks` to clear every callback at once. Both methods are safe to call even if the callback was never registered or has already self-removed. ```dart // Hold a reference to the callback function so it can be removed later KeyboardDetectionCallback myCallback = (state) { debugPrint('Analytics: keyboard $state'); return true; }; // Register _controller.registerCallback(myCallback); // Later — remove only this specific callback _controller.unregisterCallback(myCallback); // Or remove everything at once (e.g., on page exit) _controller.unregisterAllCallbacks(); ``` ``` -------------------------------- ### controller.stream Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Provides a broadcast Stream for reactive patterns. This stream is suitable for use with StreamBuilder and is automatically closed when the associated KeyboardDetection widget is disposed. ```APIDOC ## controller.stream ### Description Exposes a broadcast `Stream` for reactive patterns. Suitable for `StreamBuilder`, `StreamSubscription`, or any reactive framework. The stream is closed automatically when the associated `KeyboardDetection` widget is disposed. ### Returns - `Stream`: A broadcast stream emitting `KeyboardState` events. ``` -------------------------------- ### controller.registerCallback() Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Registers a callback function that is invoked on keyboard state changes. Callbacks can be configured to be one-shot (unregistered after first invocation by returning false) or persistent (registered indefinitely by returning true). ```APIDOC ## controller.registerCallback(KeyboardDetectionCallback callback) ### Description Registers a `FutureOr Function(KeyboardState)` callback. Returning `true` keeps the callback registered for subsequent events; returning `false` automatically unregisters it after the first invocation. Async callbacks are fully supported. ### Parameters - **callback** (KeyboardDetectionCallback) - The callback function to register. It receives the current `KeyboardState` and should return a boolean indicating whether to remain registered. ### Returns - `void` ``` -------------------------------- ### Keyboard Size Access Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Properties to read the current keyboard height and check if the size has been loaded. The keyboard size is a shared static field. ```APIDOC ## `controller.size` and `controller.isSizeLoaded` — Read the keyboard height `size` returns the keyboard height in logical pixels as a `double` (0.0 if not yet measured). `isSizeLoaded` is a synchronous `bool` that is `true` once the first stable measurement has been captured. The keyboard size is shared across all controller instances (stored as a static field) and persists for the application lifetime. ```dart // Synchronous check — useful inside build if you need a quick guard if (_controller.isSizeLoaded) { final double keyboardHeight = _controller.size; debugPrint('Keyboard height: ${keyboardHeight}px'); } // Reading size in build with a guard Widget build(BuildContext context) { return KeyboardDetection( controller: _controller, child: Scaffold( body: Column( children: [ Text( _controller.isSizeLoaded ? 'Keyboard height: ${_controller.size} px' : 'Keyboard not yet measured', ), const TextField(), ], ), ), ); } ``` ``` -------------------------------- ### Read Keyboard Height Synchronously Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Access the keyboard height using `controller.size` (a double, 0.0 if not measured) and check if it's loaded with `controller.isSizeLoaded` (a bool). The size is static and persists for the app's lifetime. ```dart // Synchronous check — useful inside build if you need a quick guard if (_controller.isSizeLoaded) { final double keyboardHeight = _controller.size; debugPrint('Keyboard height: ${keyboardHeight}px'); } // Reading size in build with a guard Widget build(BuildContext context) { return KeyboardDetection( controller: _controller, child: Scaffold( body: Column( children: [ Text( _controller.isSizeLoaded ? 'Keyboard height: ${_controller.size} px' : 'Keyboard not yet measured', ), const TextField(), ], ), ), ); } ``` -------------------------------- ### Full Stateful Widget for Keyboard Detection Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use this widget to integrate keyboard state listening, callback registration, and size measurement within a Flutter application. It manages the controller, stream subscriptions, and UI updates based on keyboard events. ```dart import 'dart:async'; import 'package:flutter/material.dart'; import 'package:keyboard_detection/keyboard_detection.dart'; void main() => runApp(const MaterialApp(home: KeyboardDemo())); class KeyboardDemo extends StatefulWidget { const KeyboardDemo({super.key}); @override State createState() => _KeyboardDemoState(); } class _KeyboardDemoState extends State { late final KeyboardDetectionController _controller; StreamSubscription? _streamSub; KeyboardState _currentState = KeyboardState.unknown; bool? _stateAsBool; @override void initState() { super.initState(); _controller = KeyboardDetectionController( onChanged: (KeyboardState state) { setState(() { _currentState = state; _stateAsBool = _controller.stateAsBool(); }); }, ); // Stream-based listener (e.g., for analytics or side effects) _streamSub = _controller.stream.listen((state) { debugPrint('[Stream] Keyboard state → $state'); }); // One-shot callback — fires only on the very first state change _controller.registerCallback((state) { debugPrint('[Callback] First keyboard event: $state'); return false; // unregisters itself }); // Persistent async callback — e.g., debounced analytics _controller.registerCallback((state) async { await Future.delayed(const Duration(milliseconds: 100)); debugPrint('[AsyncCallback] Persistent: $state'); return true; // stays registered }); } @override void dispose() { _streamSub?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return KeyboardDetection( controller: _controller, child: Scaffold( appBar: AppBar(title: const Text('keyboard_detection demo')), body: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('State (enum): $_currentState'), Text('State (bool, stable only): $_stateAsBool'), Text('State (bool, with transitions): ' '${_controller.stateAsBool(true)}'), const SizedBox(height: 8), FutureBuilder( future: _controller.ensureSizeLoaded, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return Text( 'Keyboard height: ${_controller.size.toStringAsFixed(1)}px', ); } return const Text('Keyboard height: (not yet measured)'); }, ), const SizedBox(height: 16), const TextField( decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Tap to open keyboard', ), ), ], ), ), ), ); } } // Expected console output when user taps TextField and keyboard appears: // [Stream] Keyboard state → KeyboardState.visibling // [Callback] First keyboard event: KeyboardState.visibling // [AsyncCallback] Persistent: KeyboardState.visibling // [Stream] Keyboard state → KeyboardState.visible // [AsyncCallback] Persistent: KeyboardState.visible // When dismissed: // [Stream] Keyboard state → KeyboardState.hiding // [AsyncCallback] Persistent: KeyboardState.hiding // [Stream] Keyboard state → KeyboardState.hidden // [AsyncCallback] Persistent: KeyboardState.hidden ``` -------------------------------- ### controller.state Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Reads the current KeyboardState synchronously. This getter returns the last known state without initiating new observations, making it safe for use in build methods. ```APIDOC ## controller.state ### Description Reads the current `KeyboardState` synchronously. Returns the last-known `KeyboardState` without triggering any new observation. Safe to call anywhere, including inside `build`. ### Returns - `KeyboardState`: The current state of the keyboard. ``` -------------------------------- ### Wrap Widget Tree with KeyboardDetection Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use KeyboardDetection as a StatefulWidget to wrap the widget tree that contains focusable fields. It observes inset changes and must be placed typically around the Scaffold. ```dart import 'package:flutter/material.dart'; import 'package:keyboard_detection/keyboard_detection.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { late final KeyboardDetectionController _controller; KeyboardState _state = KeyboardState.unknown; @override void initState() { super.initState(); _controller = KeyboardDetectionController( onChanged: (state) { setState(() => _state = state); }, ); } @override Widget build(BuildContext context) { // KeyboardDetection wraps the Scaffold so it can observe inset changes. return KeyboardDetection( controller: _controller, child: Scaffold( appBar: AppBar(title: const Text('Keyboard Detection Demo')), body: Column( children: [ Text('Current state: $_state'), const TextField(decoration: InputDecoration(labelText: 'Type here')), ], ), ), ); } } ``` -------------------------------- ### Simple Keyboard Detection Usage Source: https://github.com/lamnhan066/keyboard_detection/blob/main/README.md Wrap your Scaffold with KeyboardDetection and listen to the onChanged value to detect keyboard visibility changes. The onChanged callback returns a KeyboardState enum. ```dart MaterialApp( home: KeyboardDetection( controller: KeyboardDetectionController( onChanged: (value) { print('Keyboard visibility changed: $value'); setState(() { keyboardState = value; stateAsBool = keyboardDetectionController.stateAsBool(); stateAsBoolWithParamTrue = keyboardDetectionController.stateAsBool(true); }); }, ), child: Scaffold( appBar: AppBar( title: const Text('Keyboard Detection'), ), body: Center( child: Column( children: [ Text('State: $keyboardState'), Text('State as bool (includeTransitionalState = false): $stateAsBool'), Text('State as bool (includeTransitionalState = true): $stateAsBoolWithParamTrue'), const TextField(), ], ), ), ), ), ); ``` -------------------------------- ### Broadcast Stream for Reactive Patterns Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt The `controller.stream` provides a broadcast `Stream` for use with `StreamBuilder` or `StreamSubscription`. The stream is automatically closed when the `KeyboardDetection` widget is disposed. ```dart class _MyState extends State { late final KeyboardDetectionController _controller; StreamSubscription? _sub; @override void initState() { super.initState(); _controller = KeyboardDetectionController(); _sub = _controller.stream.listen((KeyboardState state) { debugPrint('Stream event: $state'); }); } @override void dispose() { _sub?.cancel(); // Always cancel to avoid leaks super.dispose(); } @override Widget build(BuildContext context) { return KeyboardDetection( controller: _controller, child: StreamBuilder( stream: _controller.stream, initialData: KeyboardState.unknown, builder: (context, snapshot) { final state = snapshot.data!; return AnimatedContainer( duration: const Duration(milliseconds: 200), color: state == KeyboardState.visible ? Colors.blue.shade50 : Colors.white, child: const TextField(), ); }, ), ); } } ``` -------------------------------- ### Register and Unregister Keyboard Callbacks Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use `registerCallback` to add a listener and `unregisterCallback` or `unregisterAllCallbacks` to remove them. Callbacks can be safely removed even if not registered or already self-removed. ```dart // Hold a reference to the callback function so it can be removed later KeyboardDetectionCallback myCallback = (state) { debugPrint('Analytics: keyboard $state'); return true; }; // Register _controller.registerCallback(myCallback); // Later — remove only this specific callback _controller.unregisterCallback(myCallback); // Or remove everything at once (e.g., on page exit) _controller.unregisterAllCallbacks(); ``` -------------------------------- ### Register Self-Managing Callbacks Source: https://context7.com/lamnhan066/keyboard_detection/llms.txt Use `controller.registerCallback()` to add callbacks that can be automatically unregistered. Returning `false` from a callback removes it after the first invocation, while returning `true` keeps it active. ```dart _controller.registerCallback((KeyboardState state) { // One-shot: fires once then is automatically removed debugPrint('First keyboard event: $state'); return false; }); _controller.registerCallback((KeyboardState state) { // Persistent: fires on every state change debugPrint('Persistent callback: $state'); return true; }); _controller.registerCallback((KeyboardState state) async { // Async persistent: useful for logging, analytics, etc. await Future.delayed(const Duration(milliseconds: 50)); debugPrint('Async callback: $state'); return true; }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.