From 0e677ed2438c9bf5f4f1c4e8edf85b22fcbb780e Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 23 Sep 2024 07:59:33 -0700 Subject: [PATCH] Fix `` with floating keyboard on iPad (#44859) Summary: On iPadOS, users can change the kind of keyboard displayed onscreen, going from normal keyboard, to split keyboard (one half on the left of the screen, one half on the right), or a floating keyboard that you can move around the screen. When a non-normal kind of keyboard is used, `` calculations are all wrong and, depending on the `behavior` prop, can make your screen completely hidden. This PR attempts to detect that the keyboard is not the "normal displayed-at-bottom-of-screen" keyboard, and forces `enable={false}` if this happens. The approach of comparing the keyboard width with the window width comes from this comment: https://github.com/facebook/react-native/issues/29473#issuecomment-696658937 A better fix might be to detect the kind of keyboard used, but this involves native code changes and I do not know iOS enough to do that. In addition, I have not found an easy way to do it using iOS APIs after a quick search. I also chose to cache the window width as a class attribute. Maybe this is not needed as `Dimensions.get('window').width` is very fast and can be called on every keyboard event? This fixes https://github.com/facebook/react-native/issues/44068 and https://github.com/facebook/react-native/issues/29473 [IOS] [FIXED] - Fix `` with floating keyboard on iPadOS Pull Request resolved: https://github.com/facebook/react-native/pull/44859 Test Plan: Tested using RNTester and the "Keyboard Avoiding View with different behaviors" example. Before: https://github.com/facebook/react-native/assets/42070/111598a3-286c-464d-8db8-73afb35cd7f9 After: https://github.com/facebook/react-native/assets/42070/0b3bc94f-8b67-4f42-8a83-e11555080268 Reviewed By: cortinico Differential Revision: D62844854 Pulled By: cipolleschi fbshipit-source-id: 577444be50019572955a013969d78178914b5b8d --- .../Components/Keyboard/KeyboardAvoidingView.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js index e26d6771c47209..860118dc38375e 100644 --- a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -9,6 +9,7 @@ */ import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; +import type {DimensionsPayload} from '../../Utilities/NativeDeviceInfo'; import type { ViewLayout, ViewLayoutEvent, @@ -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'; @@ -66,6 +68,7 @@ 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); @@ -130,6 +133,10 @@ 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; @@ -145,6 +152,15 @@ 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); @@ -178,6 +194,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 = [