- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 128
fix: interactive keyboard dismissal on iOS 26 #975
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking βSign up for GitHubβ, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
+62
β15
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
π Package size report
|
1cb8f01
to
819d196
Compare
Loading status checksβ¦
819d196
to
b6b9b9e
Compare
2 tasks
kirillzyusko
added a commit
that referenced
this pull request
Aug 1, 2025
Loading
Loading status checksβ¦
## π Description Introduce compat `KeyboardTrackingView` layer. ## π‘ Motivation and Context Starting from iOS beta 4 we got breaking changes that breaks `react-native-keyboard-controller`. ### 1οΈβ£ `layer.presentation` doesn't update its values during animation When we read `print("kv: \(KeyboardViewLocator.shared.resolve()?.layer.presentation()?.frame.origin.y)")` it will always give us values as "keyboard already opened": ```bash kv: Optional(528.0) kv: Optional(528.0) kv: Optional(528.0) kv: Optional(528.0) kv: Optional(528.0) kv: Optional(528.0) kv: Optional(528.0) ``` So it will cause "instant" animations and it's not something that developers expect to see. ### 2οΈβ£ `layer` doesn't contain the information about its `CAAnimation` While this problem is not such a critical, because we use fallback approach: if `animation` is `nil` then we just previous keyboard frame without additional frame correction. But it'll produce unsynchronized animation (we literally will come back to `[email protected]` version or earlier). So eventually we need to have an access to these variables. <hr> It's obvious that we need to get a tracking view to deliver smooth animations. I had few ideas how to add it: ### 1οΈβ£ Use `Notification` approach The first approach was to use keyboard notifications, put tracking view outside of visible screen area and track it. It works, but it'll give `CASpringAnimation` after interactive gesture dismissal (when keyboard goes up). I've tried various ideas, like changing frame without `UIView.animate` etc., but in all cases I got the same outcome: - animation can be `nil`; - animation may be `CASpringAnimation` instead of `CABasicAnimation`. ### 2οΈβ£ Use `inputAccessoryView` as tracking view The other idea was to setup listener on `inputAccessoryView`. In reality this view doesn't have any animation - I assume it's because of the fact, that it's attached to keyboard and keyboard drives the animation. _**Theoretically**_ we could lookup to `superview` and track its animation, but I didn't verify it - that solution would be pretty complex because we had to inject `inputAccessoryView` for each `TextInput`... ### 3οΈβ£ Use `keyboardLayoutGuide` for creating tracking view The other idea to try was usage of `keyboardLayoutGuide`. The idea the same as with `Notifications`. BUT! Fortunately that approach always gives proper animations and I can see `CABasicAnimation` for interactive dismissal case. This is how it looks if we make the view visible: https://github.com/user-attachments/assets/efef1976-1940-4a98-82d9-114f10df4022 The benefit of this approach is that we always can see how a native view behaves - react-native just replicates the native view. One limitation is that `keyboardLayoutGuide` is available from iOS 15. Moreover we use `usesBottomSafeArea` property, which is available starting from iOS 17. Taking all these facts into consideration and keeping in mind, that everything was pretty stable until iOS 26, I decided to use old implementation for all iOS version < 26. I don't want to break old code, but discovering bugs in new code/iOS is kind of expected process π <hr> With the new concept of a compat layer (`KeyboardTrackingView`) we can separate concepts and move all interpolation code into `KeyboardTrackingView` class itself. As a proof of concept I fixed interactive keyboard dismissal for iOS 26+ - now we can embed all math for calculating keyboard position into this layer π (so this PR will automatically close #975 - note it doesn't mean that I fully fixed interactive dismissal: this PR is a first step into making `react-native-keyboard-controller` codebase more predictable/enhanceable etc.): https://github.com/user-attachments/assets/5dda7a96-42d1-43ad-8cbd-7ca24828d0d1 Closes #975 ## π’ 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 --> ### iOS - created `KeyboardTrackingView` as a compat layer (iOS < 26 and iOS 26+) - use `KeyboardTrackingView` in `KeyboardMovementObserver` and avoid direct usages of `keyboardView` instance; - move interactive interpolation code into `KeyboardTrackingView` from `KeyboardMovementObserver`. ## π€ How Has This Been Tested? Tested manually on: - iPhone 6s (iOS 15.8, real device); - iPhone 11 (iOS 26, real device) - iPhone 16 Pro (iOS 26, real device) - iPhone 14 Pro (iOS 18.4, real device) - iPhone 15 Pro (iOS 17.5, simulator) - iPhone 16 Pro (iOS 26, simulator) ## πΈ Screenshots (if appropriate): |Before|After| |-------|-----| |<video src="https://github.com/user-attachments/assets/e2c808dc-2aa5-4768-8974-4df429abba57">|<video src="https://github.com/user-attachments/assets/04448303-be1a-4c0b-b705-fe0c936726ad">| > captured with a fix for `did` events (dispatch them only after keyboard finish its animation) for both before/after cases. Captured on iOS 26 for better proof/visibility. ## π Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
π bug
Something isn't working
π interactive keyboard
Anything related to interactive keyboard dismissing
π iOS
iOS specific
iOS 26
Anything specific to iOS 26
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
π Description
π‘ Motivation and Context
Closes #973
π’ Changelog
JS
iOS
Android
π€ How Has This Been Tested?
πΈ Screenshots (if appropriate):
π Checklist