こんにちは!207株式会社 ソフトウェアエンジニアの若月(@wktq)です。
React Nativeで横画面に対応する際に少しクセがあったので、備忘録を兼ねてまとめてみました。
react-native-orientationは使わない
「React Native orientation」などで検索すると最初に出てくるreact-native-orientationですが、 4~5年前に最終更新されてからほとんどメンテされていない状態です(以下参照)。
かわりにreact-native-orientation-lockerを使いましょう。 github.com
react-native-orientation-lockerの使い方
セットアップ
パッケージの導入
yarn add react-native-orientation-locker
iOSはAppDelegate.mを以下のように修正します。
+#import "Orientation.h" @implementation AppDelegate // ... +- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { + return [Orientation getOrientation]; +} @end
AndroidはAndroidManifest.xmlとMainActivity.javaを以下のように修正します。
AndroidManifest.xml
<activity .... + android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:windowSoftInputMode="adjustResize"> .... </activity>
MainActivity.java
+ @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Intent intent = new Intent("onConfigurationChanged"); + intent.putExtra("newConfig", newConfig); + this.sendBroadcast(intent); + } ... +import org.wonday.orientation.OrientationActivityLifecycle; @Override public void onCreate() { + registerActivityLifecycleCallbacks(OrientationActivityLifecycle.getInstance()); }
上記のセットアップが完了すると、デフォルトでデバイスを横にした際に画面が90度回転するようになります。
実装
react-native-orientation-lockerでできることは大まかに以下の2つです。
- 横画面回転をロックするか解除するかを決める
- 画面が回転した際のイベントリスナーを設定する
react-native-orientation-lockerでは、まずlandscapeモードが解除されます。 以下をAppDelegateまたはMainApplicationに追記することで、デバイスを横にした際に画面が自動的に90度回転するようになります。
その上で、内部のJSコード上でその回転をロックするかどうかを以下のように記述することができます。
import Orientation from 'react-native-orientation-locker'; ... useEffect(() => { if (lockToPortrait) { Orientation.lockToPortrait(); } else { Orientation. unlockAllOrientations(); } }, [lockToPortrait]); ...
また、イベントリスナーについては2種類あります。
- addOrientationListener -> 実際に画面が回転した際に発火。lockToPortrait()していれば画面が回転されないので発火しない。
- addDeviceOrientationListener -> デバイスの自動回転オプションやlockToPortrait()されているかに関係なくデバイスの向きが変わったら発火。
↓ 詳しくはこちら github.com
一般的に方向に応じてレイアウト変更などを行う場合にはaddOrientationListenerを使用するかと思います。 hooksコンポーネントの場合、以下のように記述します。(typescript)
onOrientationDidChange = (orientation: OrientationType) => { if (orientation == 'LANDSCAPE-LEFT') { //do something with landscape left layout } else { //do something with portrait layout } }; useEffect(() => { Orientation.addOrientationListener(onOrientationDidChange); return () => { Orientation.removeOrientationListener(onOrientationDidChange); } }, []);
OrientationTypeは以下のいずれかを返します。 "PORTRAIT" | "LANDSCAPE-LEFT" | "LANDSCAPE-RIGHT" | "PORTRAIT-UPSIDEDOWN" | "UNKNOWN"
おわりに
ちょっとクセがあるreact-nativeでの横画面対応について書いてみました。 複雑な実装ではないのですが、ライブラリの仕様の掴み所が分かるような内容になるよう意識して書きました。 ご参考になれば幸いです。
We're Hiring
207株式会社では、レガシーな物流業界の変革に挑む配達員向け効率化アプリ「TODOCUサポーター」を開発しています。 開発チームでは一緒に開発してくれるアプリエンジニア(React Native)やバックエンドエンジニアの仲間を大絶賛募集中です!
もし少しでもご興味がありましたら、以下のnotionをご覧ください!