diff --git a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js index 3159bfabd7e..08fdf276faa 100644 --- a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -9,7 +9,6 @@ */ import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; -import type {DimensionsPayload} from '../../Utilities/NativeDeviceInfo'; import type { ViewLayout, ViewLayoutEvent, @@ -19,7 +18,6 @@ import type {KeyboardEvent, KeyboardMetrics} from './Keyboard'; import LayoutAnimation from '../../LayoutAnimation/LayoutAnimation'; import StyleSheet from '../../StyleSheet/StyleSheet'; -import Dimensions from '../../Utilities/Dimensions'; import Platform from '../../Utilities/Platform'; import {type EventSubscription} from '../../vendor/emitter/EventEmitter'; import AccessibilityInfo from '../AccessibilityInfo/AccessibilityInfo'; @@ -68,7 +66,6 @@ class KeyboardAvoidingView extends React.Component { viewRef: {current: React.ElementRef | null, ...}; _initialFrameHeight: number = 0; _bottom: number = 0; - _windowWidth: number = Dimensions.get('window').width; constructor(props: Props) { super(props); @@ -115,6 +112,12 @@ class KeyboardAvoidingView extends React.Component { this._updateBottomIfNecessary(); }; + _onKeyboardHide = (event: ?KeyboardEvent) => { + this._keyboardEvent = null; + // $FlowFixMe[unused-promise] + this._updateBottomIfNecessary(); + }; + _onLayout = async (event: ViewLayoutEvent) => { event.persist(); @@ -135,10 +138,6 @@ class KeyboardAvoidingView extends React.Component { } }; - _onDimensionsChange = ({window}: DimensionsPayload) => { - this._windowWidth = window?.width ?? 0; - }; - // Avoid unnecessary renders if the KeyboardAvoidingView is disabled. _setBottom = (value: number) => { const enabled = this.props.enabled ?? true; @@ -154,15 +153,6 @@ class KeyboardAvoidingView extends React.Component { return; } - if ( - Platform.OS === 'ios' && - this._windowWidth !== this._keyboardEvent.endCoordinates.width - ) { - // The keyboard is not the standard bottom-of-the-screen keyboard. For example, floating keyboard on iPadOS. - this._setBottom(0); - return; - } - const {duration, easing, endCoordinates} = this._keyboardEvent; const height = await this._relativeKeyboardHeight(endCoordinates); @@ -200,8 +190,14 @@ class KeyboardAvoidingView extends React.Component { if (Platform.OS === 'ios') { this._subscriptions = [ - Keyboard.addListener('keyboardWillChangeFrame', this._onKeyboardChange), - Dimensions.addEventListener('change', this._onDimensionsChange), + // When undocked, split or floating, iOS will emit + // UIKeyboardWillHideNotification notification. + // UIKeyboardWillChangeFrameNotification will be emitted before + // UIKeyboardWillHideNotification, so we need to listen to + // keyboardWillHide and keyboardWillShow instead of + // keyboardWillChangeFrame. + Keyboard.addListener('keyboardWillHide', this._onKeyboardHide), + Keyboard.addListener('keyboardWillShow', this._onKeyboardChange), ]; } else { this._subscriptions = [ diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 1a6ce01d197..d3581254467 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -1792,12 +1792,11 @@ declare class KeyboardAvoidingView extends React.Component { viewRef: { current: React.ElementRef | null, ... }; _initialFrameHeight: number; _bottom: number; - _windowWidth: number; constructor(props: Props): void; _relativeKeyboardHeight(keyboardFrame: KeyboardMetrics): Promise; _onKeyboardChange: $FlowFixMe; + _onKeyboardHide: $FlowFixMe; _onLayout: $FlowFixMe; - _onDimensionsChange: $FlowFixMe; _setBottom: $FlowFixMe; _updateBottomIfNecessary: $FlowFixMe; componentDidUpdate(_: Props, prevState: State): void; diff --git a/packages/react-native/React/CoreModules/RCTKeyboardObserver.mm b/packages/react-native/React/CoreModules/RCTKeyboardObserver.mm index ce483ddceb9..79f4f8f4170 100644 --- a/packages/react-native/React/CoreModules/RCTKeyboardObserver.mm +++ b/packages/react-native/React/CoreModules/RCTKeyboardObserver.mm @@ -9,6 +9,7 @@ #import #import +#import #import "CoreModulesPlugins.h" @@ -117,6 +118,10 @@ static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification) static_cast([userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]); NSInteger isLocalUserInfoKey = [userInfo[UIKeyboardIsLocalUserInfoKey] integerValue]; + UIWindow *window = RCTKeyWindow(); + beginFrame = [window convertRect:beginFrame fromCoordinateSpace:window.screen.coordinateSpace]; + endFrame = [window convertRect:endFrame fromCoordinateSpace:window.screen.coordinateSpace]; + return @{ @"startCoordinates" : RCTRectDictionaryValue(beginFrame), @"endCoordinates" : RCTRectDictionaryValue(endFrame),