【ReactNative】キーボード表示時のレイアウト調整
はじめに
React Nativeでは、キーボード表示時のレイアウト調整を簡単に行うために、KeyboadAvoidingView というコンポーネントが用意されています。このコンポーネントを活用することで、入力フォームがキーボードに隠れてしまう問題を解消できます。
しかし、実際に使用してみるとその挙動がわかりづらく、思い通りに動作させるために少し工夫が必要でした。
そこで今回、KeyboardAvoidingView
の使い方やポイントを整理し、備忘録として記事にまとめました。
目次
- 基本的な使用方法
- スペースを縮めて調整
- Viewの移動量を調整
- フォーカスごとの挙動変更
1. 基本的な使用方法
今回、以下のようなレイアウトを KeyboardAvoidingView
を使用して調整します。
以下のコードでは KeyboardAvoidingView
を使用して、キーボード表示時のレイアウト調整を行っています。
import './global.css';
import React from 'react';
import {
KeyboardAvoidingView,
TextInput,
SafeAreaView,
Text,
View,
Keyboard,
TouchableWithoutFeedback,
} from 'react-native';
function App(): React.JSX.Element {
return (
<SafeAreaView className="flex-1">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<KeyboardAvoidingView className="flex-1" behavior="padding">
<View className="gap-y-[20px]">
<Text>デモテキスト</Text>
<View className="flex-row mb-60">
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
</View>
<View className="gap-y-[8px]">
<Text>デモテキスト</Text>
<TextInput className="h-[48px] w-full border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-full border-[1px] rounded-full p-3" />
</View>
</View>
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
</SafeAreaView>
);
}
export default App;
ここでは、TouchableWithoutFeedback を使用して、画面がタップ時にキーボードを閉じるように設定しています。また、KeyboardAvoidingView
によってキーボード表示時のレイアウト調整を設定しています。
KeyboardAvoidingView
に behavior="padding"
を設定すると、キーボードを表示時に padding-bottom
が追加されるのですが、現状の実装では以下のように上手く動作しません。
なぜ動かないかに関しては、KeyboardAvoidingView not working properly? Check your Flexbox Layout first の記事がとても分かりやすかったです。詳しい内容については、ぜひ上記の記事を確認してください。
キーボードに応じた調整を有効にするためには、justify-content: flex-end;
でレイアウトを下寄せにし、その下に flex: 1
の View を配置します。
こうすることで、キーボードが表示された時に flex: 1
のスペースが縮小し、さらに View が上に移動するようになります。
// ...
function App(): React.JSX.Element {
return (
<SafeAreaView className="flex-1">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<KeyboardAvoidingView className="flex-1 justify-end" behavior="padding">
<View className="gap-y-[20px]">
// ...
</View>
<View className="flex-1" />
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
</SafeAreaView>
);
}
export default App;
2. スペースを縮めて調整
KeyboadAvoidingView
は flex
で指定されたスペースを縮小することでレイアウトを調整します。
以下のコードでは、margin(mb-60)
を flex(flex-[40%])
に修正して、中央部分のスペースを利用することでレイアウトを調整しています。
// ...
function App(): React.JSX.Element {
return (
<SafeAreaView className="flex-1">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<KeyboardAvoidingView className="flex-1 justify-end" behavior="padding">
<View className="gap-y-[20px] flex-1">
<Text>デモテキスト</Text>
<View className="flex-row flex-[40%]">
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
</View>
<View className="gap-y-[8px]">
<Text>デモテキスト</Text>
<TextInput className="h-[48px] w-full border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-full border-[1px] rounded-full p-3" />
</View>
</View>
<View className="flex-1" />
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
</SafeAreaView>
);
}
export default App;
このように、flex
を使用することで、縮小するスペースを調整することができます。
3. Viewの移動量を調整
KeyboadAvoidingView
では、padding
や margin
が縮まらないため、これらの値を調整することで View の移動量を調整できます。
以下のコードでは、margin-bottom(mb-16)
を追加することで、View の移動量を調整しています。
// ...
function App(): React.JSX.Element {
return (
<SafeAreaView className="flex-1">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<KeyboardAvoidingView className="flex-1 justify-end" behavior="padding">
<View className="gap-y-[20px] flex-1 mb-16">
<Text>デモテキスト</Text>
<View className="flex-row flex-[40%]">
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
</View>
<View className="gap-y-[8px]">
<Text>デモテキスト</Text>
<TextInput className="h-[48px] w-full border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-full border-[1px] rounded-full p-3" />
</View>
</View>
<View className="flex-1" />
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
</SafeAreaView>
);
}
export default App;
このように、padding
や margin
を使用することで、View の移動量を調整することができます。
4. フォーカスごとの挙動変更
下のフォームにフォーカスが当たった時だけ View を移動させたいということがあったので、その際の実装方法をご紹介します。
以下のコードでは、onFocus
と onBlur
を活用してフォームのフォーカス状態を検知し、状態に応じて margin
を切り替えることで実現しています。
// ...
import React, {useState} from 'react';
import {twMerge} from 'tailwind-merge';
function App(): React.JSX.Element {
const [isBottomFocus, setBottomFocus] = useState(false);
return (
<SafeAreaView className="flex-1">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<KeyboardAvoidingView className="flex-1 justify-end" behavior="padding">
<View
className={twMerge(
'gap-y-[20px]',
isBottomFocus ? 'mb-16' : '-mb-80',
)}>
<Text>デモテキスト</Text>
<View className="flex-row mb-60">
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
<TextInput className="h-[48px] w-1/2 border-[1px] rounded-full p-3" />
</View>
<View className="gap-y-[8px]">
<Text>デモテキスト</Text>
<TextInput
className="h-[48px] w-full border-[1px] rounded-full p-3"
onBlur={() => setBottomFocus(false)}
onFocus={() => setBottomFocus(true)}
/>
<TextInput
className="h-[48px] w-full border-[1px] rounded-full p-3"
onBlur={() => setBottomFocus(false)}
onFocus={() => setBottomFocus(true)}
/>
</View>
</View>
<View className="flex-1" />
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
</SafeAreaView>
);
}
export default App;
このように実装することで、フォーカスごとの挙動を変更することができます。
まとめ
今回、KeyboardAvoidingView
の使い方についてまとめました。
初めは KeyboardAvoidingView
の挙動が掴めなかったのですが、
behavior="padding"
を設定した時にpadding-bottom
が追加されるflex
で指定されたスペースを縮小する
の2つのポイントを押さえておくことで、柔軟にレイアウトを調整することができそうです。
こちらの記事が少しでもお役に立てば幸いです。最後までご覧いただきありがとうございます。