以下の2本立てです。
- React Nativeで画面回転したらAndroidの場合にレイアウトが崩れてしまったので対応した
- 今度はKeyboardAvoidingViewが効かなくなったので代替策で回避した
環境
- React Native 0.61.5
- iOS 13.5.1
- Android 10
React Nativeで画面回転したらレイアウト崩れが発生した
KeyboardAvoidingViewをrootに配置した画面をPortrait=>Landscape=>Portraitと回転させると、謎の空間が発生。AndroidでFlexが正しく動いていないような挙動をしました。
ソースはこのような感じです。
class Hoge extends React.Component {
render() {
return (
<KeyboardAvoidingView
style={{
flex: 1
}}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
// ...
</KeyboardAvoidingView>
);
}
);
色々と解決方法を探して手当り次第試してみたところ、StackOverflowで見つけた方法で、stateを介して再renderさせるようにすることで正しくレイアウトされるようになりました。
class Hoge extends React.Component {
_onLayout = () => {
this.setState({ width: Dimensions.get('window').width });
}
render() {
return (
<KeyboardAvoidingView
onLayout={this._onLayout}
style={{
flex: 1,
width
}}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
// ...
</KeyboardAvoidingView>
);
}
);
これにて一件落着・・と思いきや、、
今度はKeyboardAvoidingViewが効かなくなった
上記の対応を行うことで、iOS・Androidともに、KeyboardAvoidingViewがキーボードを避けないただのViewと化してしまいました。
Viewの入れ子関係を入れ替えたり、色々試してみたがうまくいかず。結局KeyboardAvoidingViewをあきらめ、代わりにKeyboardSpacerというライブラリを使うとうまくいきました。
class Hoge extends React.Component {
_onLayout = ({nativeEvent}) => {
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
const screenOffset = height - nativeEvent.layout.height;
this.setState({ width, screenOffset });
};
render() {
return (
<View
onLayout={this._onLayout}
style={{
flex: 1,
width
}}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
// ...
<KeyboardSpacer topSpacing={(-1) * this.state.screenOffset} />
</View>
);
}
);
はじめはAndroidで思うように機能しませんでしたが、AndroidManifestに windowSoftInputMode="adjustResize"
を指定するとうまく動くようになりました。
また、ReactNavigationのBottomTabNavigatorを使用しているため、WindowのサイズとViewのサイズの差分を計算し、 KeyboardSpacer
の topSpacing
に設定しています。
おわりに
画面回転つながりで、iPhoneでLandscapeにしたときにステータスバーが消える影響でレイアウトが崩れる問題も発生していたので、ステータスバーの高さをstoreで管理するようにしたりしました。
こういう小細工が色々と必要なのがツラいところです。
そろそろ温泉にでも行きたいですねぇ。