You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: predictive back gesture handler (correct end event) (#814)
## 📜 Description
Fixed incorrect `end` event after cancelling predictive back gesture.
## 💡 Motivation and Context
The problem was in fact that when keyboard gets shown in `onEnd`
callback we get keyboard height as `0`, because insets were not applied
yet.
I had this problem two years ago (when I implemented interactive
keyboard dismissal), but back to the times I solved it via adding
`InteractiveProvider.isShown` and it was working well, because the only
one class could control keyboard position and it was my class. However
starting from Android 15 keyboard position can be controlled by OS
itself, so the trick with `InteractiveProvider.isShown` is not working
anymore.
After discovering various approaches how to handle it I found only two
ways:
#### 1️⃣ Pre-save insets in `onApplyWindowInsets`
While it seems preferable option, I still don't understand how it can be
utilized in that fix, because `onApplyWindowInsets` will be dispatched
in the beginning of the animation and in `onEnd` we will not be able to
determine whether keyboard has been actually closed or returned back.
> [!WARNING]
> The approach with saving last keyboard height in `onProgress` handler
and based on that dispatch an event in `onEnd` may be not good, because
keyboard animation can be interrupted and potentially it can cause more
bugs, see
#704
for more details
#### 2️⃣ Check insets after layout pass
This seems to be one and the most reliable solution (though it adds a
delay to `onEnd` event, but in my understanding it's not very critical).
With this approach we can be sure, that all new insets are applied and
we can reak keyboard frame properly.
<hr>
Upcoming questions that popped up in my head:
- **should we remove `InteractiveKeyboardProvider` completely/should we
consider predictive back gesture dismissal as interactive keyboard
dismissal** - is a good question, but if we do this, we'll treat back
predictive gesture as interactive keyboard dismissal (in fact it is
interactive dismissal), and in this case we'll send `onInteractive`
instead of `onMove`. It can be a breaking change and people (including
me) may associate `onInteractive` event only to be present with
`KeyboardGestureArea`, so for now let's keep it for a sake of backward
compatibility.
- **is async the only one way to manage this? Can't we pre-memoize
`start`/`onApplyInsets` and re-use it there?** - at the moment I don't
understand how memoization of insets in `onApplyInsets`/`onStart` can
help us to detect final keyboard position in `onEnd`. Maybe it's doable,
but for now let's stick with async approach. If we discover a new way
how to handle everything synchronously we always can re-work that piece
of the code and improve it 😎
Closes#810
## 📢 Changelog
<!-- High level overview of important changes -->
<!-- For example: fixed status bar manipulation; added new types
declarations; -->
<!-- If your changes don't affect one of platform/language below - then
remove this platform/language -->
### Android
- added `isKeyboardInteractive` getter;
- wrap `onEnd` body in `Runnable`;
- based on `isKeyboardInteractive` either execute `runnable` immediately
or after a layout pass;
- removed `InteractiveProvider.isShown`;
## 🤔 How Has This Been Tested?
Tested manually on Pixel 7 Pro (Android 15).
## 📸 Screenshots (if appropriate):
https://github.com/user-attachments/assets/2f6e41dc-b1e9-4187-b703-5c0682c84bf4
## 📝 Checklist
- [x] CI successfully passed
- [x] I added new mocks and corresponding unit-tests if library API was
changed
0 commit comments