블로그 목록
apps

expo-screen-orientation으로 화면 방향 제어하기 — 평소엔 세로 고정, 영상만 가로로

앱을 만들다 보면 대부분 화면은 세로(portrait)로 고정하고 싶은데, 영상 플레이어나 이미지 뷰어 같은 특정 화면만 가로(landscape)를 허용하고 싶을 때가 있다. 그냥 app.json에 "orientation": "portrait"를 박아두면 전역으로 세로가 고정돼서 영상 화면에서도 돌아가질 않는다. 반대로 "default"로 풀어두면 모든 화면이 기기 방향을 따라가서 리스트 화면이 눕는 꼴을 봐야 한다.

이 간극을 메우는 게 expo-screen-orientation이다. 전역 기본값은 세로로 잠가두고, 필요한 화면에서만 코드로 가로를 열었다 닫는 식이다.

설치와 기본 잠금

npx expo install expo-screen-orientation

app.json에는 기본값만 세로로 둔다.

{
  "expo": {
    "orientation": "portrait"
  }
}

영상 화면에서만 가로 허용하기

핵심은 화면이 열릴 때 가로를 풀고, 떠날 때 다시 세로로 잠그는 것. useEffect의 클린업에서 원복하는 게 포인트다.

import { useEffect } from 'react';
import * as ScreenOrientation from 'expo-screen-orientation';

function VideoScreen() {
  useEffect(() => {
    // 이 화면에서는 가로/세로 모두 허용
    ScreenOrientation.unlockAsync();

    return () => {
      // 나갈 때 다시 세로로 고정
      ScreenOrientation.lockAsync(
        ScreenOrientation.OrientationLock.PORTRAIT_UP
      );
    };
  }, []);

  return /* 플레이어 UI */;
}

unlockAsync()는 기기 설정과 물리적 방향을 그대로 따라간다. "전체화면 버튼을 눌렀을 때만 강제로 눕히고 싶다"면 unlock 대신 가로로 직접 잠그면 된다.

async function enterFullscreen() {
  await ScreenOrientation.lockAsync(
    ScreenOrientation.OrientationLock.LANDSCAPE
  );
}

async function exitFullscreen() {
  await ScreenOrientation.lockAsync(
    ScreenOrientation.OrientationLock.PORTRAIT_UP
  );
}

현재 방향 감지하기

레이아웃을 방향에 따라 바꿔야 한다면 리스너를 건다.

useEffect(() => {
  const sub = ScreenOrientation.addOrientationChangeListener((e) => {
    const o = e.orientationInfo.orientation;
    const isLandscape =
      o === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
      o === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
    // isLandscape로 UI 분기
  });
  return () => ScreenOrientation.removeOrientationChangeListener(sub);
}, []);

주의할 점

iOS 시뮬레이터에서는 app.json의 orientation 설정이 캐시돼서 코드로 잠가도 안 먹힐 때가 있다. 앱을 완전히 지웠다 다시 빌드하면 해결된다. 그리고 lockAsync는 비동기라 화면 전환 애니메이션과 타이밍이 겹치면 살짝 덜컹거릴 수 있는데, 전환이 끝난 뒤 InteractionManager.runAfterInteractions로 미루면 부드럽다.

전역은 세로로 잠그고 화면 단위로만 예외를 두는 이 패턴이, 방향 관련 코드를 한 화면 안에 가둬두기 때문에 나중에 관리하기 제일 깔끔했다.