Skip to content

Commit

Permalink
Fix <KeyboardAvoidingView> with floating keyboard on iPad
Browse files Browse the repository at this point in the history
  • Loading branch information
renchap committed Jun 10, 2024
1 parent a8f4f1d commit 463070e
Showing 1 changed file with 30 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
import type {ScaledSize} from '../../Utilities/Dimensions';
import type {
ViewLayout,
ViewLayoutEvent,
Expand All @@ -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';
Expand Down Expand Up @@ -53,6 +55,7 @@ type Props = $ReadOnly<{|

type State = {|
bottom: number,
floating: boolean,
|};

/**
Expand All @@ -66,10 +69,11 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
viewRef: {current: React.ElementRef<typeof View> | 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();
}

Expand Down Expand Up @@ -130,12 +134,15 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
}
};

_onDimensionsChange = ({window}: ScaledSize) => {
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}));
}
};

Expand All @@ -145,6 +152,14 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
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);

Expand All @@ -154,8 +169,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {

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,
Expand All @@ -167,17 +181,24 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
}
};

_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,
}));
}
}

componentDidMount(): void {
if (Platform.OS === 'ios') {
this._subscriptions = [
Keyboard.addListener('keyboardWillChangeFrame', this._onKeyboardChange),
Dimensions.addEventListener('change', this._onDimensionsChange),
];
} else {
this._subscriptions = [
Expand Down

0 comments on commit 463070e

Please sign in to comment.