LoginSignup
27

More than 5 years have passed since last update.

react-native: キーボードを開くと入力欄が隠れる問題の解決法

Posted at

React Nativeの<TextInput>にフォーカスが当たると、iOSではキーボードが下から上がってきてUIの上に重なるが、React Nativeは入力欄が画面上に見える状態で表示されていることまでは面倒を見てくれない。

たとえば、入力欄が画面の最下部にあるようなUIでは、入力欄がキーボードですっかり隠れてしまう。

failure.gif

解決策としては、コンポーネント側でキーボードの開閉イベントを受け取り、キーボードが表示されたとき、UIを上にずらすような処理をコーディングする。

UIをずらす方法として、merginTopにマイナス値をセットする、heightを減少するといった方法を試してみたものの計算や調整が難しかった。最終的に行き着いたのは、キーボードと同じ高さの<View>を画面最下部に追加してやる方法。

下のアニメーションはこの方法を実装したデモで、青い部分がキーボードと同じ高さの<View>になっている。

animation.gif

このキーボード用スペースコンポーネントの実装は次のようになる。

KeyboardSpace.js
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カーブをカスタムすることもできるので、気になる場合は微調整してみてください…。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27