I got the same issue before and i have 2 different solutions , Both of them worked for me.
1- Using react-native-keyboard-aware-scroll-view , Note that this library will already contain scrollView so you remove your own scroll view and use
<KeyboardAwareScrollView>
<View>
<TextInput />
</View>
</KeyboardAwareScrollView>
You can also check documentation for more info.
This solution is easier as you don't need to handle anything by yourself, but i think you will have some issues if you want to include scrollView inside it.
2- I once created a component AvoidKeyboard that actually does something similar to your solution, but it used to translate top the whole view with the keyboard height value, this solution worked perfectly also for me.
Implementation
import React, { Component } from 'react';
import { Animated, Easing, Keyboard } from 'react-native';
import PropTypes from 'prop-types';
class AvoidKeyboard extends Component {
constructor(props) {
super(props);
this.state = {
animatedViewHeight: new Animated.Value(0),
viewHeight: 0,
};
this.setViewHeightOnce = this.setViewHeightOnce.bind(this);
this.keyboardWillShow = this.keyboardWillShow.bind(this);
this.keyboardWillHide = this.keyboardWillHide.bind(this);
this.keyboardDidShowListener = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow);
this.keyboardDidHideListener = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide);
}
componentWillUnmount() {
this.keyboardDidShowListener && this.keyboardDidShowListener.remove();
this.keyboardDidHideListener && this.keyboardDidHideListener.remove();
}
setViewHeightOnce(event) {
const { height } = event.nativeEvent.layout;
if (this.state.viewHeight === 0) {
const avoidPaddingBottom = 15;
this.setState({
viewHeight: height + avoidPaddingBottom,
animatedViewHeight: new Animated.Value(height + avoidPaddingBottom),
});
}
}
keyboardWillShow(e) {
const { viewHeight } = this.state;
if (viewHeight) {
requestAnimationFrame(() => { // eslint-disable-line no-undef
Animated.timing(this.state.animatedViewHeight, {
toValue: (viewHeight - e.endCoordinates.height),
duration: 200,
delay: 0,
easing: Easing.inOut(Easing.ease),
}).start();
});
}
}
keyboardWillHide() {
requestAnimationFrame(() => { // eslint-disable-line no-undef
Animated.timing(this.state.animatedViewHeight, {
toValue: this.state.viewHeight,
duration: 200,
delay: 0,
easing: Easing.inOut(Easing.ease),
}).start();
});
}
render() {
let animatedHeight;
const { viewHeight } = this.state;
if (viewHeight > 0) {
animatedHeight = { maxHeight: this.state.animatedViewHeight };
}
return (
<Animated.View
style={[{ flex: 1, justifyContent: 'flex-end' }, animatedHeight]}
onLayout={this.setViewHeightOnce}
>
{this.props.children}
</Animated.View>
);
}
}
AvoidKeyboard.propTypes = {
children: PropTypes.node.isRequired,
};
export default AvoidKeyboard;
Now you just need to wrap your component or screen inside AvoidKeyboard and your screen height will shrink once keyboard is open, and you will be able to scroll the screen