From 8858a502eef2448f5667375a0562deeadffff0c7 Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Wed, 31 Aug 2022 07:48:27 -0700 Subject: [PATCH] fix: KeyboardAvoidingView height when "Prefer Cross-Fade Transitions" is enabled (#34503) Summary: Fix `KeyboardAvoidingView` height on iOS when "Prefer Cross-Fade Transitions" is enabled by adding an additional check to `_relativeKeyboardHeight` verifying if `prefersCrossFadeTransitions()` is true and `keyboardFrame.screenY` is `0` and treating this special case. The issue was caused by the native RCTKeyboardObserver where the `endFrame` reported by `UIKeyboardWillChangeFrameNotification` returns `height = 0` when Prefer Cross-Fade Transitions" is enabled and unfortunelly there isn't much we can do on the native side to fix it. Closes https://github.com/facebook/react-native/issues/31484 Closes https://github.com/facebook/react-native/issues/29974 ## Changelog [iOS] [Fixed] - Fix KeyboardAvoidingView height when "Prefer Cross-Fade Transitions" is enabled Pull Request resolved: https://github.com/facebook/react-native/pull/34503 Test Plan: **On iOS 14+** 1. Access Settings > "General" > "Accessibility" > "Reduce Motion", enable "Reduce Motion" then enable "Prefer Cross-Fade Transitions". 2. Open the RNTester app and navigate to the KeyboardAvoidingView page 3. Focus and blur inputs and observe the keyboard behaving correctly https://user-images.githubusercontent.com/11707729/186822671-801872be-7db1-4c5c-904b-1987441c1326.mov Reviewed By: jacdebug Differential Revision: D39055213 Pulled By: cipolleschi fbshipit-source-id: fac17cbe02867e0fe522397f6cb59a8b51c1840f # Conflicts: # Libraries/Components/Keyboard/KeyboardAvoidingView.js --- .../Keyboard/KeyboardAvoidingView.js | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/Libraries/Components/Keyboard/KeyboardAvoidingView.js index 4536402c5104f6..6a343d895c8ca5 100644 --- a/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -22,7 +22,8 @@ import type { ViewLayout, ViewLayoutEvent, } from '../View/ViewPropTypes'; -import type {KeyboardEvent, KeyboardEventCoordinates} from './Keyboard'; +import type {KeyboardEvent, KeyboardMetrics} from './Keyboard'; +import AccessibilityInfo from '../AccessibilityInfo/AccessibilityInfo'; type Props = $ReadOnly<{| ...ViewProps, @@ -71,12 +72,24 @@ class KeyboardAvoidingView extends React.Component { this.viewRef = React.createRef(); } - _relativeKeyboardHeight(keyboardFrame: KeyboardEventCoordinates): number { + async _relativeKeyboardHeight( + keyboardFrame: KeyboardMetrics, + ): Promise { const frame = this._frame; if (!frame || !keyboardFrame) { return 0; } + // On iOS when Prefer Cross-Fade Transitions is enabled, the keyboard position + // & height is reported differently (0 instead of Y position value matching height of frame) + if ( + Platform.OS === 'ios' && + keyboardFrame.screenY === 0 && + (await AccessibilityInfo.prefersCrossFadeTransitions()) + ) { + return 0; + } + const keyboardY = keyboardFrame.screenY - (this.props.keyboardVerticalOffset ?? 0); @@ -90,7 +103,7 @@ class KeyboardAvoidingView extends React.Component { this._updateBottomIfNecessary(); }; - _onLayout = (event: ViewLayoutEvent) => { + _onLayout = async (event: ViewLayoutEvent) => { const wasFrameNull = this._frame == null; this._frame = event.nativeEvent.layout; if (!this._initialFrameHeight) { @@ -99,7 +112,7 @@ class KeyboardAvoidingView extends React.Component { } if (wasFrameNull) { - this._updateBottomIfNecessary(); + await this._updateBottomIfNecessary(); } if (this.props.onLayout) { @@ -107,14 +120,14 @@ class KeyboardAvoidingView extends React.Component { } }; - _updateBottomIfNecessary = () => { + _updateBottomIfNecessary = async () => { if (this._keyboardEvent == null) { this.setState({bottom: 0}); return; } const {duration, easing, endCoordinates} = this._keyboardEvent; - const height = this._relativeKeyboardHeight(endCoordinates); + const height = await this._relativeKeyboardHeight(endCoordinates); if (this.state.bottom === height) { return;