1. Qiita
  2. 投稿
  3. reactnative

React Native で TextInput がソフトウェアキーボードに隠れてしまう問題の対処方法

  • 8
    いいね
  • 0
    コメント

【React Native】TextInputがキーボードに隠れてしまう問題の解決法について にて npm で簡単に解決する方法があります。package.json の dependencies を増やしたくない方はこちらをどうぞ。

現象

スクリーンショットにある様に ScrollView の下の方に TextInput が配置されていると、ソフトウェアキーボードが表示されると TextInput が隠れてしまいます。

スクリーンショット 2017-01-10 16.04.45.png

これは困った。

スクリーンショット 2017-01-10 16.04.51.png

勝手にこのようになってもらいたいものですよね。

スクリーンショット 2017-01-10 16.04.33.png

解決方法

以下、サンプルソースコード。

import React, {Component} from 'react';
import ReactNative, {
  Keyboard,
  ScrollView,
  StyleSheet,
  TextInput,
  View
} from 'react-native';

export default class MyComponent extend Component {
  constructor(props) {
    super(props);
  }

  componentWillMount() {
    this.keyboardWillShowListener = Keyboard.addListener('keyboardWillShow', this._handleKeyboardWillShow.bind(this));
  }

  componentWillUnmount() {
    this.keyboardWillShowListener.remove();
  }

  render() {
    return (
      <ScrollView
        ref={(component) => this._scrollview = component}
        style={styles.container}
      >
        <View
          style={styles.dummy}
        />
        <TextInput
          ref={(component) => this._textinput = component}
          style={styles.input}
        />
        <View
          style={styles.dummy}
        />
      </ScrollView>
    );
  }

  _handleKeyboardWillShow() {
    const responder = this._scrollview.getScrollResponder();
    responder.scrollResponderScrollNativeHandleToKeyboard(
      ReactNative.findNodeHandle(this._textinput),
      100,
      true
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column'
  },
  dummy: {
    height: 1000
  },
  input: {
    height: 44,
    borderWidth: 1,
    borderColor: '#000000'
  }
});

keyboardWillShow でソフトウェアキーボードが表示されたかどうか監視します。表示されたら ScrollView から getScrollResponder() して scrollResponderScrollNativeHandleToKeyboard() します。第一引数に TextInput の node handle が必要になりますので、ReactNative.findNodeHandle() で取得しましょう(React.findNodeHandle() は削除されているので ReactNative の方を使ってください)。第二引数でキーボードからどのくらい上にスクロールさせるか offset を指定できます。0 にするとちょうど見えなくなってしまいますので、ご自身で良い感じの数値を指定してください。今回は 100 を指定しています。第三引数を true にしておけば、算出されるスクロール値がマイナスになった時 0 にしてくれます。

ちなみに、TextInput の onFocus でスクロールさせようとしてはいけません。ソフトウェアキーボードがまだ表示されていないにも関わらず、フォーカスが当たった時点でスクロールさせようとしてしまいます。結果、正常なスクロール値が算出できず、期待通りに動いてくれません。setTimeout() でタイミングをずらしてあげてもよいのですが、せっかく keyboardWillShow があるのでそちらを使いましょう。

まとめ

getScrollResponder() とか scrollResponderScrollNativeHandleToKeyboard() は Docs に記載されていません。IDE を使っているとコードジャンプしてくれるので楽に辿ることができます。この機会に React Native 自体のソースコードを見てみるのも良いですね。
また、そもそも ScrollView に配置されていないとスクロールさせることはできませんので、TextInput は ScrollView と併用ですね。今回は ScrollView ですが、ListView でも同様のことができると思います(未検証ですが)。