창 크기 클래스 사용

Compose 사용해 보기
Jetpack Compose는 Android에 권장되는 UI 도구 키트입니다. Compose에서 창 크기 클래스를 사용하는 방법을 알아봅니다.

창 크기 클래스는 반응형/적응형 레이아웃을 디자인, 개발, 테스트하는 데 도움이 되는 체계적인 표시 영역 중단점입니다. 중단점은 레이아웃 단순성과 고유한 사례에 맞춰 앱을 최적화하는 유연성 사이의 균형을 유지합니다.

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

그림 1. 너비 기반 창 크기 클래스의 표현
그림 2. 높이 기반 창 크기 클래스의 표현

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

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

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

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

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

낮은 높이 높이 < 480dp 가로 모드 휴대전화의 99.78%
중간 높이 480dp ≤ 높이 < 900dp 가로 모드 태블릿의 96.56%

세로 모드 휴대전화의 97.59%

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

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

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

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

창 크기 클래스는 Material Design 레이아웃 안내의 소형, 중형, 확장 중단점에 매핑됩니다. 창 크기 클래스를 사용하면 추가 화면 공간을 활용하기 위해 특정 표준 레이아웃을 사용하도록 결정하는 등 애플리케이션 레이아웃을 대략적으로 결정할 수 있습니다.

您可以计算当前的 WindowSizeClass 使用 WindowSizeClass#compute() Jetpack 提供的函数, WindowManager 库。以下示例 显示了如何计算窗口大小类别,并在 窗口大小类别变更:

KotlinJava
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 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)
                computeWindowSizeClasses
()
           
}
       
})

        computeWindowSizeClasses
()
   
}

   
private fun computeWindowSizeClasses() {
       
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
       
val width = metrics.bounds.width()
       
val height = metrics.bounds.height()
       
val density = resources.displayMetrics.density
       
val windowSizeClass = WindowSizeClass.compute(width/density, height/density)
       
// COMPACT, MEDIUM, or EXPANDED
       
val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass
       
// COMPACT, MEDIUM, or EXPANDED
       
val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass

       
// Use widthWindowSizeClass and heightWindowSizeClass.
   
}
}
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 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);
                computeWindowSizeClasses
();
           
}
       
});

        computeWindowSizeClasses
();
   
}

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

       
int width = metrics.getBounds().width
       
int height = metrics.getBounds().height()
       
float density = getResources().getDisplayMetrics().density;
       
WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density)
       
// COMPACT, MEDIUM, or EXPANDED
       
WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass()
       
// COMPACT, MEDIUM, or EXPANDED
       
WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass()

       
// Use widthWindowSizeClass and heightWindowSizeClass.
   
}
}

창 크기 클래스 테스트

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

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

다음 단계

창 크기 클래스를 사용하여 반응형/적응형 레이아웃을 만드는 방법을 자세히 알아보려면 다음을 참고하세요.

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