keyboard(android): pre-R IME tracking + flush dirty marks during persistent callback
KeyboardPlugin.setupInsetsCallback used to early-return on SDK < R, so the FFI height stayed at 0 on API 29 devices like the Huawei Mate 20 Pro — the chat composer never tracked the IME. Run the global-layout listener on all SDKs, and on pre-R also wire setOnApplyWindowInsetsListener since EMUI 10's IME-hide dispatches new insets without a follow-up layout pass. Pre-R IME height comes from systemWindowInsetBottom − stableInsetBottom (stable insets exclude things that animate in/out). Inside XKeyboard._onFrame, follow notifyListeners with an explicit scheduleFrame. _onFrame runs as a persistent frame callback after the build phase has finished, so setState in listeners marks elements dirty but ensureVisualUpdate is a no-op in this phase — the steady-state pump masked the issue while the keyboard was open but on the close-edge (h transitions to 0) the pump stops and the final rebuild was never scheduled.
This commit is contained in:
@@ -229,9 +229,16 @@ class XKeyboard with ChangeNotifier {
|
||||
if ((h - _height).abs() > 0.5) {
|
||||
_height = h;
|
||||
notifyListeners();
|
||||
// notifyListeners triggers setState in listeners, which marks elements
|
||||
// dirty. We're inside a persistent frame callback (after the build phase
|
||||
// has already run), so `ensureVisualUpdate` is a no-op — without an
|
||||
// explicit scheduleFrame the dirty marks never get flushed. This matters
|
||||
// especially on the down-edge (h transitions to 0) where the steady-state
|
||||
// pump below stops scheduling.
|
||||
SchedulerBinding.instance.scheduleFrame();
|
||||
}
|
||||
|
||||
// Schedule frames while the curve is still running.
|
||||
// Steady-state pump while the curve is still running or the keyboard is up.
|
||||
final curveActive = _isAnimating &&
|
||||
(ts - _animStartTime) < _animDuration;
|
||||
if (curveActive || (!Platform.isIOS && (h > 0 || _height > 0))) {
|
||||
|
||||
Reference in New Issue
Block a user