JavaScript
reactnative

react-navigationとreact-native-orientationを組み合わせて特定のページの画面向きを固定する

実現したいこと

  • react-navigationを使ったアプリで特定のページのみ画面を横向き固定にしたい
  • 戻るボタンで戻ってきたような場面でもちゃんと指定した通りに固定させたい

実現方法

react-native-orientationのメソッド

  • lockToPortrait()
    • 縦向きにロックする
  • lockToLandscape()
    • 横向きにロックする
  • lockToLandscapeLeft()
    • 左辺が下に来るように横向きにロックする
  • lockToLandscapeRight()
    • 右辺が下に来るように横向きにロックする
  • unlockAllOrientations()
    • ロックを解除する

react-navigationとの連携

  • 遷移の度に呼ばれるonNavigationStateChangeを活用してページ遷移ごとに処理をはさむ
  • 横向き固定にしたい画面のリストを持っておき、リストに含まれる画面に遷移した場合画面をロックする

サンプル

  • A->B->Cの順に遷移する3つのページがある
  • AとCは縦固定、Bは横固定にするサンプル
index.ios.js/index.android.js
import React from 'react';
import { AppRegistry } from 'react-native';
import AppNavigator from './app/navigators/AppNavigator';
import { onNavigationStateChange } from './app/utils/Utils';

// onNavigationStateChange属性に渡した関数はページ遷移が行われるたび(=stateが更新される度)に呼ばれます
const ReactNativeSample = () => <AppNavigator onNavigationStateChange={onNavigationStateChange} />

AppRegistry.registerComponent('ReactNativeSample', () => ReactNativeSample);
app/navigators/AppNavigator.js
import { StackNavigator } from 'react-navigation'
import SampleAScreen from '../containers/SampleAScreen'
import SampleBScreen from '../containers/SampleBScreen'
import SampleCScreen from '../containers/SampleCScreen'

const AppNavigator = StackNavigator({
  SampleA: { screen: SampleAScreen },
  SampleB: { screen: SampleBScreen },
  SampleC: { screen: SampleCScreen },
})

// 横向き固定したい画面リスト
export const landscapeOrientationScreens = ['SampleB']
export default AppNavigator
app/utils/Utils.js
import Orientation from 'react-native-orientation';
import { landscapeOrientationScreens } from '../navigators/AppNavigator';

const handleOrientation = (currentRouteName) => {
  // 受け取った引数が横向き固定したいリストに含まれていたら横向きにロック、そうでなかったら縦向きにロック
  landscapeOrientationScreens.includes(currentRouteName) ?
    Orientation.lockToLandscapeLeft() :
    Orientation. lockToPortrait();
}

// ページ遷移する度に呼ばれる
export const onNavigationStateChange = (prevState, currentState) => {
  const routes = currentState.routes;
  const currentRouteName = routes[routes.length - 1].routeName;
  // 遷移後の画面名を引数に渡す
  handleOrientation(currentRouteName);
}
  • こんな感じで画面Bだけ横向き固定されている

orientation.gif


追記

  • このサンプルだと最初のページで画面固定がきいていなかった
  • index.android.js, index.ios.jsのcomponentWillMountにOrientation. lockToPortrait()を書いておけば対応できる