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: properly report height for didShow event happening during animation (#557)
## 📜 Description
Fixed a case when `onEnd`/`keyboardDidShow` reports incorrect (previous
frame) keyboard height.
## 💡 Motivation and Context
Fixes regressions introduced in
#539
Initially I thought it's safe to read current keyboard frame in
`didAppear` lifecycle (I thought it'll be always dispatched after
animation finish, so why not to read it). But it was a fatal mistake
because:
- when keyboard changes its size it changes it immediately and in
`didAppear` we'll read old (previous) value ⛔
- on iOS 15 when modal gets hidden, then keyboard appears instantly and
iOS 15 dispatches only one event, so we'll read old frame (i. e. `0`); 🔴
- when iOS 17 with `secureTextEntry` randomly attaches/detaches
`inputAccessoryView`, then we may also encounter a situation, when we
read old frame and we will avoid keyboard incorrectly ❌
So to sum up all previous approaches:
- relying on `duration === 0` is not reliable because keyboard can be
hidden immediately but with `duration === 250` 🤯
- reading current frame in `keyboardDidShow` is not correct approach
because in some situations we may read old values 😔
This PR is a third revision of the solution 😂 Now I learned all lessons
(at least I hope so) and invented a better mechanism. Let's go back to
original problem.
The original problem was in the fact, that a resize event can be
dispatched during animation AND it'll contain incorrect information
about keyboard size (it'll have final destination, though animation
hasn't finished yet). I decided to catch that situation in the code - I
added `didShowDeadline` variable and in `keyboardWillAppear` I set it as
`timestamp + duration`. In `keyboardDidAppear` I verify, that this event
arrived later, and if so, then we read `keyboardHeight` value from
`notification`. Otherwise, if event `didShow` was received before
deadline (i. e. resize event) we can not read data from notification (as
it may not reflect a real state of the things) and instead we are
reading it from keyboard view layer (falling back to what is actually
shown on the screen). Schematically pipeline looks like:
<img width="687" alt="image"
src="https://github.com/user-attachments/assets/a5fd7b2f-ee8c-4c86-82fc-d017bb01f363">
I think such approach is safer and it looks like it will fix all known
issues and at the same time it doesn't introduce additional complexity
to the JS codebase.
Fixes#327 (comment)Expensify/App#47679
## 📢 Changelog
### iOS
- added `didShowDeadline` variable;
- initialize `didShowDeadline` in `willAppear`;
- check if `didShowDeadline` is bigger than current timestamp, and if
yes, then only then read values from layer. Otherwise as before - from a
notification
## 🤔 How Has This Been Tested?
Tested manually on many devices.
## 📸 Screenshots (if appropriate):
### iOS 15
|Before|After|
|-------|-----|
|<video
src="https://github.com/user-attachments/assets/8253efaa-a20e-4566-b747-7676b6c6cd1e">|<video
src="https://github.com/user-attachments/assets/988340c6-da7e-40f5-bcd2-6ec95e7d1ea4">|
### Keyboard resize
|Before|After|
|-------|-----|
|<video
src="https://github.com/user-attachments/assets/6d008543-38b1-46e3-b792-b4ef813fea77">|<video
src="https://github.com/user-attachments/assets/fc7108d7-e996-4568-8f6e-1cefdf7a3e9a">|
### `KeyboardAvoidingView`
|Before|After|
|-------|-----|
|<video
src="https://github.com/user-attachments/assets/d43f8b53-d442-4a42-a573-d3a2e30a04ad">|<video
src="https://github.com/user-attachments/assets/c7cfe29e-7467-497f-9f4d-b824956f50d6">|
## 📝 Checklist
- [x] CI successfully passed
- [x] I added new mocks and corresponding unit-tests if library API was
changed
0 commit comments