휴대전화 및 폴더블 외부 화면에서 앱 방향을 제한하고 더 큰 디스플레이에서는 제한하지 않기

앱이 세로 모드의 휴대전화에서 잘 작동하므로 앱을 세로 모드로만 사용하도록 제한했습니다. 하지만 대형 화면의 가로 모드 방향 또는 펼쳐진 폴더블에서 더 많은 작업을 할 수 있는 경우가 있습니다.

폴더블의 외부 화면에서는 세로 모드 방향으로 앱을 제한하고 내부 화면에서는 가로 모드를 사용할 수 있도록 두 가지 방법을 모두 제공하려면 어떻게 해야 할까요?

이 가이드는 모든 기기 구성을 완벽하게 지원하도록 앱을 개선할 수 있게 되기까지의 임시 조치입니다.

결과

앱은 기기 회전과 관계없이 작은 화면에서 세로 모드 방향으로 유지됩니다. 대형 화면에서는 앱이 가로 모드 방향과 세로 모드 방향을 지원합니다.

버전 호환성

이 구현은 모든 API 수준과 호환됩니다.

종속 항목

Kotlin

implementation("androidx.window:window:1.5.1")
implementation("androidx.window:window-core:1.5.1")

Groovy

implementation "androidx.window:window:1.5.1"
implementation "androidx.window:window-core:1.5.1"

앱 방향 관리

대형 화면에서 가로 모드 방향을 사용 설정하려면 앱 매니페스트가 기본적으로 방향 변경을 처리하도록 설정합니다. 런타임 시 앱 창 크기를 결정합니다. 앱 창이 작은 경우 매니페스트 방향 설정을 재정의하여 앱 방향을 제한합니다.

1. 앱 매니페스트에 방향 설정 지정

앱 매니페스트의 screenOrientation 요소를 선언하지 않거나 (이 경우 방향 기본값이 unspecified가 됨) 화면 방향을 fullUser로 설정할 수 있습니다. 사용자가 센서 기반 회전을 잠그지 않은 경우 앱은 모든 기기 방향을 지원합니다.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

unspecifiedfullUser의 차이는 미묘하지만 중요합니다. screenOrientation 값을 선언하지 않으면 시스템이 방향을 선택하며, 시스템에서 방향을 정의하는 데 사용하는 정책은 기기마다 다를 수 있습니다.

반면에 fullUser를 지정하면 사용자가 기기에 정의한 동작에 더 가까워집니다. 사용자가 센서 기반 회전을 잠근 경우에는 앱이 사용자 환경설정을 따르고, 그러지 않은 경우에는 시스템이 네 가지 화면 방향 (세로 모드, 가로 모드, 세로 반전, 가로 반전)을 허용합니다.

또한 nosensor를 사용하여 센서 데이터를 고려하지 않고 방향을 결정할 수 있지만 다음 코드는 동일한 방식으로 작동합니다. 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 객체로 가져옵니다. 창 측정항목을 창 크기 클래스와 비교하여 방향을 제한할 시점을 결정할 수 있습니다.

창 크기 클래스는 작은 화면과 큰 화면 사이에 중단점을 제공합니다.

WindowSizeClass#minWidthDpWindowSizeClass#minHeightDp 중단점을 사용하여 화면 크기를 결정합니다.

/** 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 =
        BREAKPOINTS_V1.computeWindowSizeClass(width / density, height / density)
    return windowSizeClass.minWidthDp == 0
}

앱에서 computeMaximumWindowMetrics() 메서드를 사용할 수 있도록 종속 항목을 선언하는 방법은 WindowManager를 참고하세요.

3. 앱 매니페스트 설정 재정의

기기의 화면 크기가 작다는 것을 확인했다면 Activity#setRequestedOrientation()을 호출하여 매니페스트의 screenOrientation 설정을 재정의할 수 있습니다.

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
        }
    })
}

onCreate()View.onConfigurationChanged() 메서드에 로직을 추가하면 활동이 디스플레이 간에 크기가 조절되거나 이동할 때마다(예: 기기 회전 후 또는 폴더블 기기가 접히거나 펼쳐질 때) 최대 창 측정항목을 가져오고 방향 설정을 재정의할 수 있습니다. 구성 변경이 발생하는 시점과 이러한 변경사항이 활동 재생성을 유발하는 시점에 관한 자세한 내용은 구성 변경사항 처리를 참고하세요.

Jetpack Compose를 사용하는 경우 앱의 루트 Composable에서 동일한 compactScreen() 함수를 사용하여 동일한 결과를 얻을 수 있습니다.

핵심 사항

  • screenOrientation: 앱이 기기 방향 변경에 응답하는 방식을 지정할 수 있는 앱 매니페스트 설정
  • Jetpack WindowManager: 앱 창의 크기와 가로세로 비율을 결정할 수 있는 라이브러리 집합으로 API 수준 14와 하위 호환됨
  • Activity#setRequestedOrientation(): 런타임 시 앱 방향을 변경할 수 있게 해주는 메서드

이 가이드가 포함된 컬렉션

이 가이드는 광범위한 Android 개발 목표를 다루는 선별된 빠른 가이드 컬렉션의 일부입니다.

태블릿, 폴더블, ChromeOS 기기에서 최적화된 사용자 환경을 지원하도록 앱을 사용 설정합니다.

궁금한 점이나 의견이 있으신가요?

자주 묻는 질문 페이지로 이동하여 빠른 가이드에 관해 알아보거나 Google에 문의하여 의견을 알려주세요.