React NativeのTextInputで改行に応じて入力ボックスの高さ（スタイル）を変更したい

こんにちは！

今回は「React Native TextInputで改行に応じて入力ボックスのスタイルを変更する」方法について、お伝えしていきたいと思います。

今回は以下のような簡単な入力ボックスを例に説明していきたいと思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659719/931c133a-7a3c-e7c4-7617-867ebf3d00ed.gif" width="100%" />


### 改行したかどうかを取得するには`onContentSizeChange`を使う
まず、前提として、改行を有効にするには`TextInput`の`multiline={true}`を設定しておきます。

```javascript
<TextInput
  multiline={true}
/>
```

次に`TextInput`の`props`に`onContentSizeChange`を設定します。

```javascript
export default function SplashScreen() {
const [inputMsg, setInputMsg] = useState('');
return (
  <TextInput
    style={{fontSize: 50}}
    multiline={true}
    value={inputMsg}
    onContentSizeChange={(event) => {
      console.log(event.nativeEvent.contentSize); //例：Object {"height": 60, "width": 32,}
}
    }
  />
);
```
これは入力値が変わるたびに呼ばれるコールバック関数で、 `{ nativeEvent: { contentSize: { width, height } } }`を取得することができます。
今回はこの`height`の値を使用します。

※`width`は文字数に応じて変化し、`height`は改行によって変化します。
※フォントサイズなどによって、変化量も異なります。

例を使いながら、これらの値がどのように変化していくのかみていきます。

#### 例1　1文字入力した時
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659719/08039588-3c7d-56c5-80ee-b73226b38883.png" width="40%" />

出力結果は・・・

```javascript
  <TextInput
    style={{fontSize: 50}}
    multiline={true}
    value={inputMsg}
    onContentSizeChange={(event) => {
      console.log(event.nativeEvent.contentSize); 
      //出力結果： Object {"height": 60, "width": 32,}
}
    }
  />
);
```

#### 例2　1文字入力＋改行１回した時
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659719/60d1e528-ac39-102d-7ec7-b104ef82f89c.png" width="40%" />

```javascript
  <TextInput
    style={{fontSize: 50}}
    multiline={true}
    value={inputMsg}
    onContentSizeChange={(event) => {
      console.log(event.nativeEvent.contentSize); 
      //出力結果： Object {"height": 119.66666666666667, "width": 32,}
}
    }
  />
);
```

`height`の値が大きくなっていることがわかります。
この値を使って、入力ボックスのスタイルを変更したいと思います。

### 改行に応じて、入力ボックスのスタイルを変更する
改行すると、動的に入力ボックスの高さを広げるようにしてみます。
先ほどの`nativeEvent.contentSize.height`は`state`で管理します。

```javascript
export default function SplashScreen() {
  // 入力ボックスの高さはstateで管理
  const [inputHeight, setInputHeight] = useState(0);
  return (
    <View style={styles.container}>
      <View
        style={[
          // 入力ボックスの高さ = nativeEvent.contentSize.height
          styles.inputContainer, {height: inputHeight},
        ]}
      >
        <TextInput
          style={{fontSize: 50}}
          placeholder="type here..."
          multiline={true}
          onContentSizeChange={(event) => {
            // 入力ボックスの高さをsetState
            setInputHeight(event.nativeEvent.contentSize.height);
          }}
        />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems:'center',
    justifyContent:'center',
  },
  inputContainer: {
    backgroundColor: 'yellow',
    width: 300,
  },
});
```

### 入力ボックスの高さに上限を設定する
すでに動的に入力ボックスの高さを設定することができました。
しかし、今のままだと入力ボックスが画面いっぱいまで広がってしまいます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659719/b2b1c51e-b77e-ec55-60ce-a38cb500e7eb.png" width="40%" />

高さに上限を設定するために条件分岐を追加します。

```javascript

// （省略）

<TextInput
  style={{fontSize: 50}}
  placeholder="type here..."
  multiline={true}
  onContentSizeChange={(event) => {
    console.log(event.nativeEvent.contentSize);
　　 /* 入力の高さが300より大きい場合は上限値300を設定する */
    if (event.nativeEvent.contentSize.height <= 300) {
      setInputHeight(event.nativeEvent.contentSize.height);
    } else {
      setInputHeight(300);
    }
  }}
/>

// （省略）
```

これによって、高さに上限値を設定することができました。（今回は上限4行になるように調整しています）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659719/b95ed234-9aa3-9a8f-e939-797e7596bd30.png" width="40%" />

### まとめ
だいぶ簡単に書いてしまいましたが、
上記のように書くことで、入力ボックスの高さを変更することができます。
よかったら試してみてください。

### 参考
React Native公式ドキュメント
https://reactnative.dev/docs/scrollview