Skip to content

Instantly share code, notes, and snippets.

@sjmueller
Created November 15, 2017 06:39
Show Gist options
  • Save sjmueller/905b0d4cbcfacfa95128cdefaf957e70 to your computer and use it in GitHub Desktop.
Save sjmueller/905b0d4cbcfacfa95128cdefaf957e70 to your computer and use it in GitHub Desktop.
Es6 version of the KeyboardAvoidingView React Native component (stripped of every behavior except padding)
import React, { Component } from 'react';
import { Keyboard, LayoutAnimation, Platform, View } from 'react-native';
/**
* An es6 version of RN KeyboardAvoidingView, with support for iPhone X safe area
*/
class KeyboardSyncView extends Component {
constructor() {
super();
this.state = {
bottom: 0
};
this.subscriptions = [];
this.frame = null;
}
relativeKeyboardHeight(keyboardFrame) {
const frame = this.frame;
if (!frame || !keyboardFrame) {
return 0;
}
const keyboardY = keyboardFrame.screenY;
// Calculate the displacement needed for the view such that it
// no longer overlaps with the keyboard
return Math.max(frame.y + frame.height - keyboardY, 0);
}
onKeyboardChange = event => {
if (!event) {
this.setState({ bottom: 0 });
return;
}
const { duration, easing, endCoordinates } = event;
const height = this.relativeKeyboardHeight(endCoordinates);
if (duration && easing) {
LayoutAnimation.configureNext({
duration: duration,
update: {
duration: duration,
type: LayoutAnimation.Types[easing] || 'keyboard'
}
});
}
console.log(`onKeyboardChange setting bottom to ${height}`);
this.setState({ bottom: height });
};
onLayout = event => {
this.frame = event.nativeEvent.layout;
};
componentWillUpdate(nextProps, nextState): void {
if (
nextState.bottom === this.state.bottom &&
this.props.behavior === 'height' &&
nextProps.behavior === 'height'
) {
// If the component rerenders without an internal state change, e.g.
// triggered by parent component re-rendering, no need for bottom to change.
nextState.bottom = 0;
}
}
componentWillMount() {
if (Platform.OS === 'ios') {
this.subscriptions = [
Keyboard.addListener('keyboardWillChangeFrame', this.onKeyboardChange)
];
} else {
this.subscriptions = [
Keyboard.addListener('keyboardDidHide', this.onKeyboardChange),
Keyboard.addListener('keyboardDidShow', this.onKeyboardChange)
];
}
}
componentWillUnmount() {
this.subscriptions.forEach(sub => sub.remove());
}
render() {
const { children, style, ...props } = this.props;
const paddingStyle = { paddingBottom: this.state.bottom };
return (
<View
ref={viewRef => (this.viewRef = viewRef)}
style={[style, paddingStyle]}
onLayout={this.onLayout}
{...props}
>
{children}
</View>
);
}
}
export default KeyboardSyncView;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment