diff --git a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js index e26d6771c47209..2c1ed3b09305ab 100644 --- a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -8,6 +8,7 @@ * @flow strict-local */ +import type {DimensionsValue} from '../../../Utilities/Dimensions'; import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; import type { ViewLayout, @@ -18,6 +19,7 @@ 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'; @@ -53,6 +55,7 @@ type Props = $ReadOnly<{| type State = {| bottom: number, + floating: boolean, |}; /** @@ -66,10 +69,11 @@ 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); - this.state = {bottom: 0}; + this.state = {bottom: 0, floating: false}; this.viewRef = React.createRef(); } @@ -130,12 +134,15 @@ class KeyboardAvoidingView extends React.Component { } }; + _onDimensionsChange = ({window}: DimensionsValue) => { + this._windowWidth = window.width; + }; + // Avoid unnecessary renders if the KeyboardAvoidingView is disabled. _setBottom = (value: number) => { - const enabled = this.props.enabled ?? true; this._bottom = value; - if (enabled) { - this.setState({bottom: value}); + if (this._enabled()) { + this.setState(state => ({floating: state.floating, bottom: value})); } }; @@ -145,6 +152,14 @@ class KeyboardAvoidingView extends React.Component { return; } + if ( + Platform.OS === 'ios' && + this._windowWidth !== this._keyboardEvent.endCoordinates.width + ) { + this._setBottom(0); + return; + } + const {duration, easing, endCoordinates} = this._keyboardEvent; const height = await this._relativeKeyboardHeight(endCoordinates); @@ -154,8 +169,7 @@ class KeyboardAvoidingView extends React.Component { this._setBottom(height); - const enabled = this.props.enabled ?? true; - if (enabled && duration && easing) { + if (this._enabled() && duration && easing) { LayoutAnimation.configureNext({ // We have to pass the duration equal to minimal accepted duration defined here: RCTLayoutAnimation.m duration: duration > 10 ? duration : 10, @@ -167,10 +181,16 @@ class KeyboardAvoidingView extends React.Component { } }; + _enabled(): boolean { + return this.props.enabled ?? true; + } + componentDidUpdate(_: Props, prevState: State): void { - const enabled = this.props.enabled ?? true; - if (enabled && this._bottom !== prevState.bottom) { - this.setState({bottom: this._bottom}); + if (this._enabled() && this._bottom !== prevState.bottom) { + this.setState(state => ({ + floating: state.floating, + bottom: this._bottom, + })); } } @@ -178,6 +198,7 @@ class KeyboardAvoidingView extends React.Component { if (Platform.OS === 'ios') { this._subscriptions = [ Keyboard.addListener('keyboardWillChangeFrame', this._onKeyboardChange), + Dimensions.addEventListener('change', this._onDimensionsChange), ]; } else { this._subscriptions = [