안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu

다양한 화면 크기를 지원하면 최대한 많은 사용자가 다양한 기기에서 앱을 사용하도록 할 수 있습니다.

가능한 한 많은 화면 크기를 지원하려면 앱 레이아웃을 반응형 및 적응형으로 디자인합니다. 반응형/적응형 레이아웃은 화면 크기와 관계없이 최적화된 사용자 환경을 제공하여 앱이 스마트폰과 태블릿, 폴더블, Chrome OS 기기, 세로 및 가로 모드, 크기 조절 가능한 구성(예: 멀티 윈도우 모드)을 수용할 수 있습니다.

창 크기 클래스

창 크기 클래스는 반응형 및 적응형 애플리케이션 레이아웃을 디자인하고 개발 및 테스트할 수 있는 체계적인 표시 영역 중단점입니다. 특히 고유의 사례에 맞춰 앱을 최적화하도록 레이아웃의 단순성과 유연성의 균형을 이루기 위해 이러한 중단점을 선택했습니다.

창 크기 클래스는 앱에서 사용할 수 있는 디스플레이 영역을 소형, 중형, 확장으로 분류합니다. 사용 가능한 너비와 높이는 개별적으로 분류되므로 언제라도 앱에는 두 가지 창 크기 클래스(너비 창 크기 클래스, 높이 창 크기 클래스)가 있습니다. 세로 스크롤이 보편적이기 때문에 사용 가능한 너비가 사용 가능한 높이보다 더 중요한 경우가 많습니다. 따라서 너비 창 크기 클래스가 앱의 UI와 더 관련이 있을 수 있습니다.

안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 1. 너비 기반 창 크기 클래스의 표현
안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 2. 높이 기반 창 크기 클래스의 표현

위의 그림과 같이 중단점을 사용하면 기기 및 구성 측면에서 레이아웃을 계속 고려할 수 있습니다. 각 크기 클래스 중단점은 일반적인 기기 시나리오의 대부분의 사례를 나타내며 중단점 기반 레이아웃의 디자인을 고려할 때 유용한 참조 기준일 수 있습니다.

크기 클래스중단점기기 표현
좁은 너비 600dp 미만 세로 모드 휴대전화의 99.96%
중간 너비 600dp 이상 세로 모드 태블릿의 93.73%

세로 모드의 펼친 대형 내부 디스플레이

확장 후 너비 840dp 이상 가로 모드 태블릿의 97.22%

가로 모드의 펼친 대형 내부 디스플레이

낮은 높이 480dp 미만 가로 모드 휴대전화의 99.78%
중간 높이 480dp 이상 가로 모드 태블릿의 96.56%

세로 모드 휴대전화의 97.59%

확장 후 높이 900dp 이상 세로 모드 태블릿의 94.25%

크기 클래스를 실제 기기로 시각화하는 것이 유용할 수 있지만 창 크기 클래스는 기기 화면의 크기에 의해 명시적으로 결정되지 않습니다. 즉, 창 크기 클래스는 isTablet-type 로직에 적합하지 않습니다. 대신 창 크기 클래스는 앱이 실행되는 기기 유형과 관계없이 애플리케이션에서 사용할 수 있는 창 크기에 따라 결정됩니다. 이에 따른 중요한 두 가지 결과가 있습니다.

  • 실제 기기는 특정 창 크기 클래스를 보장하지 않습니다. 앱에서 사용할 수 있는 화면 공간은 여러 가지 이유로 인해 기기의 화면 크기와 다를 수 있습니다. 휴대기기에서 화면 분할 모드는 두 애플리케이션 간에 화면을 분할할 수 있습니다. Chrome OS에서 Android 앱은 임의로 크기를 조절할 수 있는 자유 형식 창에 표시될 수 있습니다. 폴더블에는 기기를 접거나 펼쳐서 개별적으로 액세스할 수 있는 두 가지 크기의 화면이 있을 수 있습니다.

  • 창 크기 클래스는 앱의 전체 기간 동안 변경될 수 있습니다. 앱이 실행되는 동안 기기 방향을 변경하거나, 멀티태스킹하거나, 접거나 펼칠 때 사용 가능한 화면 공간이 변경될 수 있습니다. 따라서 창 크기 클래스는 동적이며 이에 맞게 앱의 UI가 조정되어야 합니다.

창 크기 클래스는 머티리얼 디자인 반응형 레이아웃 그리드의 레이아웃 중단점에 매핑됩니다. 창 크기 클래스를 사용하면 추가 화면 공간을 사용하기 위해 특정 표준 레이아웃을 사용하도록 결정하는 등 애플리케이션 레이아웃을 대략적으로 결정할 수 있습니다.

뷰 기반 앱은 Jetpack WindowManager 라이브러리에서 제공하는 현재 창 측정항목을 기반으로 창 크기 클래스를 계산해야 합니다. 아래의 뷰(Kotlin) 및 뷰(자바) 코드 예는 중단점을 기반으로 창 크기 클래스를 계산하고 창 크기가 변경될 때마다 업데이트를 받는 방법을 보여줍니다.

Compose 기반 앱은material3-window-size-class 라이브러리를 사용하여 calculateWindowSizeClass()로 현재 창 측정항목을 기반으로 WindowSizeClass를 계산해야 합니다.

enum class WindowSizeClass { COMPACT, MEDIUM, EXPANDED }

class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ...

        // Replace with a known container that you can safely add a
        // view to where it 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. We also 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)
                computeWindowSizeClasses()
            }
        })

        computeWindowSizeClasses()
    }

    private fun computeWindowSizeClasses() {
        val metrics = WindowMetricsCalculator.getOrCreate()
            .computeCurrentWindowMetrics(this)

        val widthDp = metrics.bounds.width() /
            resources.displayMetrics.density
        val widthWindowSizeClass = when {
            widthDp < 600f -> WindowSizeClass.COMPACT
            widthDp < 840f -> WindowSizeClass.MEDIUM
            else -> WindowSizeClass.EXPANDED
        }

        val heightDp = metrics.bounds.height() /
            resources.displayMetrics.density
        val heightWindowSizeClass = when {
            heightDp < 480f -> WindowSizeClass.COMPACT
            heightDp < 900f -> WindowSizeClass.MEDIUM
            else -> WindowSizeClass.EXPANDED
        }

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

public enum WindowSizeClass { COMPACT, MEDIUM, EXPANDED }

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        // Replace with a known container that you can safely add a
        // view to where it 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. We also 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);
                computeWindowSizeClasses();
            }
        });

        computeWindowSizeClasses();
    }

    private void computeWindowSizeClasses() {
        WindowMetrics metrics = WindowMetricsCalculator.getOrCreate()
                .computeCurrentWindowMetrics(this);

        float widthDp = metrics.getBounds().width() /
                getResources().getDisplayMetrics().density;
        WindowSizeClass widthWindowSizeClass;

        if (widthDp < 600f) {
            widthWindowSizeClass = WindowSizeClass.COMPACT;
        } else if (widthDp < 840f) {
            widthWindowSizeClass = WindowSizeClass.MEDIUM;
        } else {
            widthWindowSizeClass = WindowSizeClass.EXPANDED;
        }

        float heightDp = metrics.getBounds().height() /
                getResources().getDisplayMetrics().density;
        WindowSizeClass heightWindowSizeClass;

        if (heightDp < 480f) {
            heightWindowSizeClass = WindowSizeClass.COMPACT;
        } else if (heightDp < 900f) {
            heightWindowSizeClass = WindowSizeClass.MEDIUM;
        } else {
            heightWindowSizeClass = WindowSizeClass.EXPANDED;
        }

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

Compose

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            val windowSizeClass = calculateWindowSizeClass(this)
            MyApp(windowSizeClass)
        }
    }
}

앱에서 창 크기 클래스를 관찰한 후에는 현재 창 크기 클래스에 따라 레이아웃을 변경할 수 있습니다.

창 크기 클래스를 사용하여 레이아웃을 반응형으로 만드는 방법을 자세히 알아보려면 다음 내용을 확인하세요.

  • 뷰 기반 레이아웃은 반응형 레이아웃으로 UI 이전을 참고하세요
  • Compose 기반 레이아웃은 적응형 레이아웃 빌드하기를 참고하세요

다양한 창 크기 클래스를 지원하기 위한 체크리스트

레이아웃을 변경할 때 모든 범위의 창 크기에서, 특히 소형, 중형, 확장 중단점 너비에서 레이아웃 동작을 테스트하세요.

소형 화면의 기존 레이아웃이 있는 경우 확장 후 너비 크기 클래스에 맞게 레이아웃을 최적화합니다. 그러면 추가 콘텐츠와 UI 변경을 위한 가장 많은 공간이 제공됩니다. 그런 다음 중형 너비 크기 클래스에 적합한 레이아웃을 확인하고 중형 너비 화면 크기에 맞는 특수한 레이아웃을 추가하는 것이 좋습니다.

향상된 사용자 환경을 제공하려면 폴더블의 상태 변경을 지원하거나 키보드, 마우스, 스타일러스 입력 지원에 맞게 최적화하는 등 앱에 적합한 기능을 추가합니다.

모든 기기와 화면 크기에서 훌륭하게 작동하는 앱의 요소를 자세히 알아보려면 대형 화면 앱 품질을 참고하세요.

반응형 디자인

다양한 기기 폼 팩터를 지원하는 첫 번째 단계는 화면 크기의 변화에 반응하는 레이아웃을 만드는 것입니다.

ConstraintLayout

반응형 레이아웃을 만드는 가장 좋은 방법은 ConstraintLayout을 UI의 기본 레이아웃으로 사용하는 것입니다. ConstraintLayout을 사용하면 레이아웃에 있는 다른 뷰와의 공간적 관계에 따라 각 뷰의 위치와 크기를 지정할 수 있습니다. 이러한 방식으로 화면 크기가 변경될 때 모든 뷰가 함께 이동하고 크기를 조절할 수 있습니다.

ConstraintLayout을 사용하여 레이아웃을 빌드하는 가장 쉬운 방법은 Android 스튜디오의 Layout Editor를 사용하는 것입니다. Layout Editor를 사용하면 XML을 직접 편집하지 않고도 새로운 뷰를 레이아웃으로 드래그하고, 상위 뷰 및 동위 뷰를 기준으로 제약 조건을 적용하고, 뷰 속성을 설정할 수 있습니다.

안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 3. ConstraintLayout을 보여주는 Android 스튜디오의 Layout Editor

자세한 내용은 ConstraintLayout으로 반응형 UI 빌드를 참고하세요.

반응형 너비 및 높이

레이아웃이 다양한 화면 크기에 반응하도록 하려면 하드 코딩된 값 대신 wrap_content, match_parent 또는 0dp (match constraint)를 대부분의 뷰 구성요소의 너비와 높이에 사용해야 합니다.

  • wrap_content: 뷰가 뷰에 포함된 콘텐츠에 맞게 크기를 설정하도록 합니다.
  • match_parent: 뷰가 상위 뷰 내에서 최대한 크게 확장되도록 합니다.
  • 0dp (match constraint): ConstraintLayout에서 match_parent와 비슷하게 작동합니다. 뷰가 뷰의 제약 조건 내에서 사용 가능한 모든 공간을 차지하도록 합니다.

예를 들면 다음과 같습니다.

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

그림 4는 기기 방향에 따라 화면 너비가 변경될 때 TextView의 너비와 높이가 어떻게 조정되는지 보여줍니다.

안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 4. 반응형 TextView

TextView는 사용 가능한 모든 공간(match_parent)을 채우도록 너비를 설정하고 포함된 텍스트의 높이(wrap_content)에 필요한 공간과 정확하게 일치하도록 높이를 설정합니다. 이렇게 하면 뷰가 다양한 화면 크기와 여러 텍스트 분량에 맞게 조정될 수 있습니다.

LinearLayout을 사용하는 경우 뷰가 사용 가능한 공간을 비례하여 채우도록 레이아웃 가중치를 기준으로 하위 뷰를 확장할 수도 있습니다. 그러나 중첩 LinearLayout에서 가중치를 사용하려면 시스템이 여러 레이아웃 전달을 실행하여 각 뷰의 크기를 판단해야 하므로 UI 성능이 느려집니다.

ConstraintLayout은 성능에 영향을 미치지 않으면서 LinearLayout으로 가능한 거의 모든 레이아웃을 만들 수 있으므로 중첩된 LinearLayoutConstraintLayout으로 변환해 보세요. 그런 다음 제약 조건 체인을 사용하여 가중치 적용 레이아웃을 정의할 수 있습니다.

적응형 디자인

앱 레이아웃은 항상 다양한 화면 크기에 반응해야 합니다. 그러나 반응형 레이아웃이라고 해서 모든 기기에서 최상의 사용자 환경을 제공하는 것은 아닙니다. 예를 들어 휴대전화용으로 디자인한 UI는 태블릿에서 최적의 경험을 제공하지 못할 수 있습니다. 적응형 디자인은 다양한 디스플레이 크기에 최적화된 대체 레이아웃을 제공합니다.

목록 세부정보 UI의 SlidingPaneLayout

목록 세부정보 UI는 일반적으로 여러 크기의 화면에서 다양한 사용자 환경을 제공합니다. 큰 화면에서는 목록 창과 세부정보 창이 일반적으로 나란히 표시됩니다. 목록의 항목을 선택하면 UI가 변경되지 않고 세부정보 창에 항목 정보가 표시됩니다. 두 창은 계속 나란히 있습니다. 하지만 작은 화면에서는 두 창이 별도로 표시되고 각 창은 전체 디스플레이 영역을 차지합니다. 목록 창의 항목을 선택하면 선택된 항목의 정보가 포함된 세부정보 창이 목록 창을 대체합니다. 뒤로 탐색은 세부정보 창을 목록으로 대체합니다.

SlidingPaneLayout은 두 사용자 환경 중에서 현재 창 크기에 적합한 로직을 판단하는 작업을 담당합니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

SlidingPaneLayout에 포함된 두 뷰의 layout_widthlayout_weight 속성은 SlidingPaneLayout 동작을 결정합니다. 이 예에서 창이 두 뷰를 모두 표시할 만큼 충분히 큰 경우에는(너비 580dp 이상) 두 창이 나란히 표시됩니다. 하지만 창 너비가 580dp보다 작으면 두 창이 서로 겹쳐서 각각 전체 앱 창을 차지하게 됩니다.

창 너비가 지정된 최소 너비(580dp)보다 크면 layout_weight 값을 사용하여 두 창의 크기를 비례적으로 조정할 수 있습니다. 이 예에서 목록 창은 가중치가 없기 때문에 너비가 항상 280dp입니다. 그러나 세부정보 창은 뷰의 layout_weight로 인해 항상 580dp를 초과하는 가로 공간을 채웁니다.

대체 레이아웃 리소스

다양한 화면 크기에 맞게 UI 디자인을 조정하려면 리소스 한정자로 식별되는 대체 레이아웃을 사용합니다.

안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 5. 동일한 앱이 서로 다른 화면 크기에서 각각 서로 다른 레이아웃 사용

앱의 소스 코드에 res/layout/ 디렉터리를 추가로 만들어 화면별 적응형 레이아웃을 제공할 수 있습니다. 다른 레이아웃이 필요한 각 화면 구성별로 디렉터리를 만듭니다. 그런 다음 화면 layout 디렉터리 이름에 화면 구성 한정자를 추가합니다(예: 사용 가능한 너비가 600dp인 화면에는 layout-w600dp).

구성 한정자는 앱 UI에 사용 가능한 표시 화면 공간을 나타냅니다. 시스템은 앱의 레이아웃을 선택할 때 모든 시스템 장식(예: 탐색 메뉴) 및 창 구성 변경사항(예: 멀티 윈도우 모드)을 고려합니다.

Android 스튜디오(버전 3.0 이상 사용)에서 대체 레이아웃을 만들려면 다음을 따르세요.

  1. 기본 레이아웃을 열고 툴바에서 Orientation for Preview
    안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
    를 클릭합니다.
  2. 드롭다운 목록에서 Create Landscape Variation과 같은 추천 변형을 클릭하여 만들거나 Create Other를 클릭합니다.
  3. Create Other를 선택한 경우 Select Resource Directory가 나타납니다. 왼쪽의 화면 한정자를 선택하여 Chosen qualifiers 목록에 추가합니다. 한정자를 추가했으면 OK를 클릭합니다. 화면 크기 한정자에 관한 자세한 내용은 다음 섹션을 참고하세요.

새 레이아웃 디렉터리에 기본 레이아웃 파일의 복제본이 만들어지므로 화면 변형에 관해 레이아웃 맞춤설정을 시작할 수 있습니다.

최소 너비 한정자

최소 너비 화면 크기 한정자를 사용하면 밀도 독립형 픽셀(dp 또는 dip) 단위로 측정된 최소 너비가 있는 화면에 대체 레이아웃을 제공할 수 있습니다.

이렇게 화면 크기를 dp 단위의 측정값으로 설명하면 Android에서 다양한 픽셀 밀도에 관해 염려하지 않으면서 특정 화면 크기로 디자인된 레이아웃을 만들 수 있습니다.

예를 들어 서로 다른 디렉터리에 다른 버전의 파일을 만들어 휴대전화와 태블릿에 최적화된 main_activity라는 레이아웃을 만들 수 있습니다.

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7” tablets (600dp wide or wider)

최소 너비 한정자는 기기의 현재 방향에 상관없이 화면의 두 면이 가장 작은 것을 지정하므로 간단하게 레이아웃에 사용할 수 있는 전체 화면 크기를 지정할 수 있습니다.

다른 최소 너비 값에 해당하는 일반 화면 크기는 다음과 같습니다.

  • 320dp: 일반적인 휴대전화 화면(240x320 ldpi, 320x480 mdpi, 480x800 hdpi 등).
  • 480dp: 대형 휴대전화 화면, 최대 5인치까지(480x800 mdpi).
  • 600dp: 7인치 태블릿(600x1024 mdpi).
  • 720dp: 10인치 태블릿(720x1280 mdpi, 800x1280 mdpi 등).

그림 6에서는 다양한 화면 dp 너비와 이에 해당하는 다양한 화면 크기 및 방향에 관한 자세한 뷰를 제공합니다.

안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 6. 다양한 화면 크기를 지원하는 권장 너비 중단점

최소 너비 한정자의 값은 dp 단위입니다. 중요한 것은 시스템이 픽셀 밀도(원시 픽셀 해상도 아님)를 고려한 후 사용 가능한 화면 공간 크기이기 때문입니다.

최소 너비와 같은 리소스 한정자를 사용하여 지정하는 크기는 실제 화면 크기가 아닙니다. 이 크기는 앱 창에 사용할 수 있는 dp 단위의 너비 또는 높이를 지정합니다. Android 시스템에서는 일부 화면을 시스템 UI(예: 화면 하단의 시스템 표시줄 또는 상단의 상태 표시줄)용으로 사용할 수 있으므로, 이들 화면 중 일부에서는 레이아웃을 사용하지 못할 수 있습니다. 앱을 멀티 윈도우 모드로 사용하는 경우 앱은 앱을 포함하는 창의 크기에만 액세스할 수 있습니다. 창 크기를 조절하면 새 창 크기로 구성 변경을 트리거하므로 시스템에서 적절한 레이아웃 파일을 선택할 수 있습니다. 따라서 선언하는 리소스 한정자 크기는 앱에 필요한 공간만 지정해야 합니다. 시스템에서는 레이아웃용으로 공간을 제공할 때 시스템 UI에 사용되는 공간을 고려합니다.

사용 가능한 너비 한정자

화면의 최소 너비에 따라 레이아웃을 변경하는 대신 현재 사용 가능한 너비 또는 높이에 따라 레이아웃을 변경해야 할 수 있습니다. 예를 들어 화면의 너비가 최소 600dp가 될 때마다 창 두 개 레이아웃을 사용하고자 할 수 있습니다. 이때 화면의 너비는 기기가 가로 방향에 있는지 세로 방향에 있는지에 따라 변경될 수 있습니다. 이 경우 다음과 같이 사용 가능한 너비 한정자를 사용해야 합니다.

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7” tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

앱에서 사용 가능한 높이가 관건인 경우에는 사용 가능한 높이 한정자를 사용할 수 있습니다. 예를 들어 화면 높이가 600dp 이상인 화면의 경우 layout-h600dp입니다.

방향 한정자

최소 너비 및 사용 가능한 너비 한정자의 조합만 사용하여 모든 크기 변형을 지원할 수도 있지만 사용자가 세로 방향과 가로 방향 간에 전환할 때 사용자 환경을 변경하고자 할 수도 있습니다.

이를 위해 port 또는 land 한정자를 레이아웃 디렉터리 이름에 추가할 수 있습니다. 이러한 방향 한정자는 크기 한정자 뒤에 오도록 해야 합니다. 예를 들면 다음과 같습니다.

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7” tablets
res/layout-sw600dp-land/main_activity.xml   # For 7” tablets in landscape

모든 화면 구성 한정자에 관한 자세한 내용은 앱 리소스 개요를 참고하세요.

프래그먼트로 UI 구성요소 모듈화

여러 화면 크기에 맞게 앱을 디자인할 때는 활동 전반에 걸쳐 불필요하게 UI 동작이 중복되지 않도록 프래그먼트를 사용하여 UI 로직을 개별 구성요소로 추출해야 합니다. 그런 다음 큰 화면에서 프래그먼트를 결합하여 다중창 레이아웃을 만들거나 작은 화면에서 프래그먼트를 개별 활동에 배치할 수 있습니다.

예를 들어 목록 세부정보 패턴(위의 SlidingPaneLayout 참고)은 목록을 포함하는 하나의 프래그먼트와 목록 항목 세부정보를 포함하는 또 하나의 프래그먼트로 구현할 수 있습니다. 큰 화면에서는 프래그먼트를 나란히 표시할 수 있고, 작은 화면에서는 개별 프래그먼트가 화면을 채우도록 표시할 수 있습니다.

자세한 내용은 프래그먼트 개요를 참고하세요.

활동 삽입

앱이 여러 활동으로 구성된 경우 활동 삽입을 사용하면 쉽게 적응형 UI를 만들 수 있습니다.

활동 삽입은 애플리케이션의 작업 창에 동시에 여러 활동을 표시하거나 동일 활동의 여러 인스턴스를 표시합니다. 대형 화면에서는 활동을 나란히 표시하고 작은 화면에서는 활동을 스택으로 표시할 수 있습니다.

앱이 활동을 표시하는 방식은 XML 구성 파일을 만들어서 정합니다. 시스템에서는 XML 구성 파일을 사용하여 화면 크기를 기준으로 적절한 표시 방식을 정합니다. 또는 Jetpack WindowManager API를 호출할 수도 있습니다.

활동 삽입은 기기 방향 변경 및 폴더블 기기를 지원하며 기기가 회전하거나 접히고 펼쳐질 때 활동을 스택하고 스택 해제합니다.

자세한 내용은 활동 삽입을 참고하세요.

화면 크기 및 가로세로 비율

앱을 다양한 화면 크기와 가로세로 비율에서 테스트하여 UI 크기 조정이 올바르게 이루어지는지 확인하세요.

Android 10(API 수준 29) 및 이후 버전에서는 다양한 가로세로 비율을 지원합니다. 폴더블 폼 팩터는 접었을 때 21:9인 길고 좁은 화면부터 펼쳤을 때 1:1인 정사각형 가로세로 비율까지 다양한 비율을 가질 수 있습니다.

가능한 한 많은 기기와의 호환성을 보장하려면 가능한 한 많은 화면 가로세로 비율로 앱을 테스트하세요.

안드로이드 화면 사이즈 - andeuloideu hwamyeon saijeu
그림 7. 화면 가로세로 비율

이러한 가로세로 비율 중 일부를 지원할 수 없는 경우 maxAspectRatiominAspectRatio를 사용하여 앱에서 처리할 수 있는 가장 높은 비율과 가장 낮은 비율을 나타낼 수 있습니다. 이러한 제한을 초과하는 화면이 있는 경우 앱이 호환 모드로 지정될 수 있습니다.

테스트하고자 하는 다양한 화면 크기의 기기를 이용할 수 없다면 Android Emulator를 사용하여 거의 모든 화면 크기를 에뮬레이션할 수 있습니다.

실제 기기에서 테스트하고 싶지만 기기가 없다면 Firebase Test Lab을 사용하여 Google 데이터 센터의 기기에 액세스하면 됩니다.

특정 화면 크기 지원

앱을 특정 화면 크기에서 실행하지 않으려면 화면 크기를 조정할 수 있는 한도를 설정할 수 있습니다. 아니면 화면 구성에 따라 앱을 설치할 수 있는 기기를 제한할 수도 있습니다. 자세한 내용은 제한적 화면 지원 선언을 참고하세요.

추가 리소스

  • Material Design 3: 적응형 디자인
  • 적응형 디자인의 표준 레이아웃