TextInputのmultiline設定がAndroidだとうまく機能しない

原因は不明ですが、React-NativeではAndroid版TextInputのmultilineがうまく機能しない場合があるようです。

前提

こんな感じのTextInputを想定しています。

      <TextInput
        multiline
        blurOnSubmit={false}
        onChange={this.onChange}
      />

確認できた症例

ハードウェアキーボードから改行が入力できない

シミュレーターを利用した状況下で、PCのキーボード側からEnterキーを入力しても改行が入力されません。

日本語入力用ソフトウェアキーボードから改行が入力できない

シミュレーターを利用した状況下で、Androidのソフトウェアキーボードからリターンキーを入力しても改行が入力されません。

英語入力用ソフトウェアキーボードからは改行が入力できる

同様にシミュレーター利用下で、Androidの英語入力用キーボードからリターンキーを押すと、期待通り改行が入力されます。

改行が入力できない時は送信イベントが発火する

前2つの状況下では、改行が入力されない代わりにonSubmitEditingイベントが発火しました。これは以下の仕様に反する動作です。

onSubmitEditing?: PropTypes.func

Callback that is called when the text input’s submit button is pressed. Invalid if multiline={true} is specified.

(TextInput #onSubmitEditing)

対症療法

直接の対応方法は調べても見つかりません。発見できたのはリターンキーに反応して改行を挿入するという対症療法だけでした。

幸いにして、改行が入力されない場合にはonSubmitEditingイベントが発火するため、これを利用します。

render() {
  return (
    <TextInput
      multiline
      blurOnSubmit={false}
      onChange={this.onChange}
      value={this.state.text}
      selection={this.state.selection}
      onSelectionChange={this.onSelectionChange}
      onSubmitEditing={this.onSubmitEditing}
    />
  );
}

onSelectionChange(event) {
  this.setState({
    selection: event.nativeEvent.selection,
  });
}

onSubmitEditing = _.debounce(this._onSubmitEditing, 100, true);

_onSubmitEditingNote() {
  const { text, selection } = this.state;
  const newText = `${text.substr(0, selection.start)}\n${text.substr(selection.end, text.length)}`;
  if (selection.start === text.length) {
    this.setState({ text: newText });
  } else {
    this.setState({
      text: newText,
      selection: {
        start: selection.start + 1,
        end: selection.end + 1,
      },
    });
  }
}

改行入力後のカーソル位置変更のためだけのために、selectionをstateに突っ込まなきゃいけないので処理が増えてあまりきれいではありません。 もっと良い方法があればよいのですが。

参考