React Nativeの<TextInput>
にフォーカスが当たると、iOSではキーボードが下から上がってきてUIの上に重なるが、React Nativeは入力欄が画面上に見える状態で表示されていることまでは面倒を見てくれない。
たとえば、入力欄が画面の最下部にあるようなUIでは、入力欄がキーボードですっかり隠れてしまう。
解決策としては、コンポーネント側でキーボードの開閉イベントを受け取り、キーボードが表示されたとき、UIを上にずらすような処理をコーディングする。
UIをずらす方法として、merginTop
にマイナス値をセットする、height
を減少するといった方法を試してみたものの計算や調整が難しかった。最終的に行き着いたのは、キーボードと同じ高さの<View>
を画面最下部に追加してやる方法。
下のアニメーションはこの方法を実装したデモで、青い部分がキーボードと同じ高さの<View>
になっている。
このキーボード用スペースコンポーネントの実装は次のようになる。
import React, {Component} from "react-native";
const {
Animated,
DeviceEventEmitter
} = React;
export default class KeyboardSpace extends Component {
constructor(props, context) {
super(props, context);
this.state = {
height: new Animated.Value(0)
};
this.keyboardWillShowSubscription = null;
this.keyboardWillHideSubscription = null;
}
componentDidMount() {
DeviceEventEmitter.addListener("keyboardWillShow", (e) => this.keyboardWillShow(e));
DeviceEventEmitter.addListener("keyboardWillHide", (e) => this.keyboardWillHide(e));
}
componentWillUnmount() {
this.keyboardWillShowSubscription.remove();
this.keyboardWillHideSubscription.remove();
}
keyboardWillShow(e) {
Animated.timing(this.state.height, {
toValue: e.endCoordinates ? e.endCoordinates.height : e.end.height,
duration: e.duration
}).start();
}
keyboardWillHide(e) {
Animated.timing(this.state.height, {
toValue: 0,
duration: e.duration
}).start();
}
render() {
return (
<Animated.View style={{height: this.state.height}}></Animated.View>
);
}
}
使い方は、ずらしたいコンポーネントの後ろにおくだけ。
import React, {Component} from "react-native";
const {
View,
StyleSheet
} = React;
import KeyboardSpace from "./KeyboardSpace.js";
export default class ConversationPage extends Component {
render() {
return (
<View style={styles.container}>
...ずらしたいコンポーネントをここに配置...
<KeyboardSpace />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
なお、アニメーションがiOSのキーボード出し入れの速度と違うが、React Nativeが提供しているeasingカーブにiOSの"keyboard"相当のものがないためこうなってしまう。React NativeのAnimatedではeasingカーブをカスタムすることもできるので、気になる場合は微調整してみてください…。