앱이 세로 모드의 휴대전화에서 잘 작동하므로 앱을 세로 모드로만 사용하도록 제한했습니다. 하지만 대형 화면의 가로 모드 방향으로 더 많은 작업을 할 수 있는 경우가 있습니다.
작은 화면에서는 세로 모드 방향으로 앱을 제한하고 대형 화면에서는 가로 모드를 사용할 수 있도록 두 가지 방법을 모두 제공하려면 어떻게 해야 할까요?
이 가이드는 모든 기기 구성을 완벽하게 지원하도록 앱을 개선할 수 있을 때까지의 임시 조치입니다.
앱 방향 관리
대형 화면에서 가로 모드 방향을 사용 설정하려면 기본적으로 방향 변경을 처리하도록 앱 매니페스트를 설정합니다. 런타임 시 앱 창 크기를 결정합니다. 앱 창이 작은 경우 매니페스트 방향 설정을 재정의하여 앱 방향을 제한합니다.
1. 앱 매니페스트에 방향 설정 지정
앱 매니페스트의 screenOrientation
요소를 선언하지 않거나 (이 경우 방향 기본값이 unspecified
가 됨) 화면 방향을 fullUser
로 설정할 수 있습니다. 사용자가 센서 기반 회전을 잠그지 않은 경우 앱은 모든 기기 방향을 지원합니다.
<activity
android:name=".MyActivity"
android:screenOrientation="fullUser">
unspecified
와 fullUser
의 차이점은 미묘하지만 중요합니다. screenOrientation
값을 선언하지 않으면 시스템이 방향을 선택하며, 시스템에서 방향을 정의하는 데 사용하는 정책은 기기마다 다를 수 있습니다. 반면에 fullUser
를 지정하면 사용자가 기기에 정의한 동작에 더 근접합니다. 사용자가 센서 기반 회전을 잠근 경우 앱은 사용자 환경설정을 따르고, 그렇지 않은 경우 시스템은 가능한 네 가지 화면 방향 (세로, 가로, 세로 반전, 가로 반전) 중 하나를 허용합니다. screenOrientation
을 참고하세요.
2. 화면 크기 확인
사용자가 허용하는 모든 방향을 지원하도록 매니페스트를 설정하면 화면 크기에 따라 프로그래매틱 방식으로 앱 방향을 지정할 수 있습니다.
모듈의 build.gradle
또는 build.gradle.kts
파일에 Jetpack WindowManager 라이브러리를 추가합니다.
Kotlin
implementation("androidx.window:window:version
") implementation("androidx.window:window-core:version
")
Groovy
implementation 'androidx.window:window:version
' implementation 'androidx.window:window-core:version
'
Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics()
메서드를 사용하여 기기 화면 크기를 WindowMetrics
객체로 가져옵니다. 창 측정항목을 창 크기 클래스와 비교하여 방향을 제한할 시점을 결정할 수 있습니다.
창 크기 클래스는 작은 화면과 큰 화면 사이에 중단점을 제공합니다.
WindowWidthSizeClass#COMPACT
및 WindowHeightSizeClass#COMPACT
중단점을 사용하여 화면 크기를 결정합니다.
Kotlin
/** Determines whether the device has a compact screen. **/ fun compactScreen() : Boolean { val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT }
Java
/** Determines whether the device has a compact screen. **/ private boolean compactScreen() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this); int width = metrics.getBounds().width(); int height = metrics.getBounds().height(); float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density); return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT || windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT; }
- 참고:
- 이 예는 활동의 메서드로 구현되었습니다. 따라서 활동은
computeMaximumWindowMetrics()
의 인수에서this
로 역참조됩니다. - 앱이 멀티 윈도우 모드에서 실행될 수 있으므로
computeMaximumWindowMetrics()
가computeCurrentWindowMetrics()
대신 사용됩니다. 멀티 윈도우 모드에서는 화면 방향 설정을 무시되기 때문입니다. 앱 창이 기기 전체 화면을 차지하지 않는다면 앱 창 크기를 결정하고 방향 설정을 재정의하는 것은 의미가 없습니다.
앱에서 computeMaximumWindowMetrics()
메서드를 사용할 수 있도록 종속 항목을 선언하는 방법은 WindowManager를 참고하세요.
3. 앱 매니페스트 설정 재정의
기기의 화면이 작다는 것을 확인했다면 Activity#setRequestedOrientation()
을 호출하여 매니페스트의 screenOrientation
설정을 재정의할 수 있습니다.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER } }) }
Java
@Override protected void onCreate(Bundle savedInstance) { super.onCreate(savedInstanceState); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } } }); }
onCreate()
및 View.onConfigurationChanged()
메서드에 로직을 추가하면 활동이 디스플레이 간에 크기가 조절되거나 이동할 때마다(예: 기기 회전 후 또는 폴더블 기기가 접히거나 펼쳐질 때) 최대 창 측정항목을 가져오고 방향 설정을 재정의할 수 있습니다.
구성 변경이 발생하는 시점과 이러한 변경사항이 활동 재생성을 유발하는 시점에 관한 자세한 내용은 구성 변경 처리를 참고하세요.
핵심사항
screenOrientation
: 앱이 기기 방향 변경에 응답하는 방식을 지정할 수 있는 앱 매니페스트 설정- Jetpack WindowManager: 앱 창의 크기와 가로세로 비율을 결정할 수 있는 라이브러리 모음으로 API 수준 14와 하위 호환됨
Activity#setRequestedOrientation()
: 런타임 시 앱 방향을 변경할 수 있게 해주는 메서드
결과
이제 앱이 작은 화면에서 기기 회전과 관계없이 세로 모드 방향으로 유지될 것입니다. 대형 화면에서는 앱이 가로 모드 방향과 세로 모드 방향을 지원합니다.
이 가이드가 포함된 컬렉션
이 가이드는 광범위한 Android 개발 목표를 다루는 선별된 빠른 가이드 모음의 일부입니다.
![](https://developer.android.com/static/images/quick-guides/collection-illustration.png?hl=ko)