앱에 더 넓은 화면에 콘텐츠 표시

Compose 사용해 보기
Jetpack Compose는 Android를 위한 권장 UI 도구 키트입니다. Compose에서 더 넓은 화면을 사용하는 방법을 알아보세요.

Android 15 이상을 실행하는 기기에서 SDK 35 이상을 타겟팅하면 앱이 더 넓은 화면을 표시합니다. 창은 시스템 표시줄 뒤에 그려져 디스플레이의 전체 너비와 높이에 걸쳐 표시됩니다. 시스템 표시줄에는 상태 표시줄, 자막 표시줄, 탐색 메뉴가 포함됩니다.

많은 앱에는 상단 앱 바가 있습니다. 상단 앱 바는 화면 상단 가장자리까지 확장되어 상태 표시줄 뒤에 표시되어야 합니다. 원하는 경우 콘텐츠가 스크롤될 때 상단 앱 바가 상태 표시줄 높이로 축소될 수 있습니다.

많은 앱에는 하단 앱 바 또는 하단 탐색 메뉴도 있습니다. 또한 이 막대는 화면 하단 가장자리까지 늘어나고 탐색 메뉴 뒤에 표시되어야 합니다. 그러지 않으면 앱이 탐색 메뉴 뒤에 스크롤 콘텐츠를 표시해야 합니다.

그림 1. 더 넓은 화면 레이아웃의 시스템 표시줄

앱에서 전체 화면 레이아웃을 구현할 때는 다음 사항에 유의하세요.

  1. 더 넓은 화면 디스플레이 사용 설정
  2. 시각적 중복을 처리합니다.
  3. 시스템 표시줄 뒤에 스림을 표시하는 것이 좋습니다.
상태 표시줄 뒤에 배치된 이미지의 예
그림 2. 상태 표시줄 뒤에 있는 이미지의 예

더 넓은 화면 표시 사용 설정

앱이 SDK 35 이상을 타겟팅하는 경우 Android 15 이상 기기에서 자동으로 전체 화면이 사용 설정됩니다.

이전 Android 버전에서 전체 화면을 사용 설정하려면 다음 단계를 따르세요.

  1. 앱 또는 모듈의 build.gradle 파일에서 androidx.activity 라이브러리에 종속 항목을 추가합니다.

    Kotlin

    dependencies {
        val activity_version = activity_version
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }

    Groovy

    dependencies {
        def activity_version = activity_version
        // Java language implementation
        implementation 'androidx.activity:activity:$activity_version'
        // Kotlin
        implementation 'androidx.activity:activity-ktx:$activity_version'
    }
  2. enableEdgeToEdge 확장 함수를 앱으로 가져옵니다.

ActivityonCreate에서 enableEdgeToEdge를 호출하여 더 넓은 화면을 수동으로 사용 설정합니다. setContentView 전에 호출해야 합니다.

Kotlin

     override fun onCreate(savedInstanceState: Bundle?) {
       enableEdgeToEdge()
       super.onCreate(savedInstanceState)
       ...
     }
   

자바

     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
       EdgeToEdge.enable(this);
       super.onCreate(savedInstanceState);
       ...
     }
   

기본적으로 enableEdgeToEdge()는 상태 표시줄에 반투명한 스림이 적용되는 3버튼 탐색 모드를 제외하고 시스템 표시줄을 투명하게 만듭니다. 시스템 아이콘과 스림의 색상은 시스템 밝은 테마 또는 어두운 테마에 따라 조정됩니다.

enableEdgeToEdge() 함수는 앱이 전체 화면에 배치되어야 한다고 자동으로 선언하고 시스템 막대의 색상을 조정합니다.

enableEdgeToEdge() 함수를 사용하지 않고 앱에서 더 넓은 화면 표시를 사용 설정하려면 더 넓은 화면 표시 수동 설정을 참고하세요.

인셋을 사용하여 중복 처리

일부 앱 뷰는 그림 3과 같이 시스템 표시줄 뒤에 그려질 수 있습니다.

화면에서 탐색 메뉴 또는 상태 표시줄과 같은 시스템 UI와 교차하는 부분을 지정하는 인셋에 반응하여 겹침을 해결할 수 있습니다. 교차는 콘텐츠 위에 표시되는 것을 의미할 수도 있지만 앱에 시스템 동작을 알릴 수도 있습니다.

앱을 전체 화면에 표시하는 데 적용되는 인셋 유형은 다음과 같습니다.

  • 시스템 표시줄 인셋: 탭할 수 있고 시스템 표시줄에 의해 시각적으로 가려져서는 안 되는 뷰에 가장 적합합니다.

  • 디스플레이 컷아웃 인셋: 기기의 모양으로 인해 화면 컷아웃이 있을 수 있는 영역입니다.

  • 시스템 동작 인셋: 시스템에서 사용하며 앱보다 우선순위가 높은 동작 탐색 영역입니다.

시스템 표시줄 인셋

시스템 표시줄 인셋은 가장 일반적으로 사용되는 인셋 유형입니다. 시스템 UI가 앱 위의 Z축에 표시되는 영역을 나타냅니다. 탭할 수 있고 시스템 표시줄에 의해 시각적으로 가려져서는 안 되는 앱의 뷰를 이동하거나 패딩하는 데 가장 적합합니다.

예를 들어 그림 3의 플로팅 작업 버튼 (FAB)은 탐색 메뉴에 의해 부분적으로 가려져 있습니다.

화면 전체가 구현되었지만 탐색 메뉴가 FAB를 가리는 예
그림 3. 전체 화면 레이아웃에서 FAB와 겹치는 탐색 메뉴

동작 모드 또는 버튼 모드에서 이러한 종류의 시각적 겹침을 방지하려면 WindowInsetsCompat.Type.systemBars()와 함께 getInsets(int)를 사용하여 뷰의 여백을 늘리면 됩니다.

다음 코드 예는 시스템 표시줄 인셋을 구현하는 방법을 보여줍니다.

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets ->
  val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
  // Apply the insets as a margin to the view. This solution sets
  // only the bottom, left, and right dimensions, but you can apply whichever
  // insets are appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  v.updateLayoutParams<MarginLayoutParams> {
      leftMargin = insets.left
      bottomMargin = insets.bottom
      rightMargin = insets.right
  }

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
  WindowInsetsCompat.CONSUMED
}

자바

ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. This solution sets only the
  // bottom, left, and right dimensions, but you can apply whichever insets are
  // appropriate to your layout. You can also update the view padding if that's
  // more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

이 솔루션을 그림 3에 나온 예에 적용하면 그림 4와 같이 버튼 모드에서 시각적 중복이 발생하지 않습니다.

FAB를 가리지 않는 반투명 탐색 메뉴
그림 4. 버튼 모드에서 시각적 중복을 해결합니다.

동작 탐색 모드에도 동일하게 적용됩니다(그림 5 참고).

동작 탐색이 있는 더 넓은 화면
그림 5. 동작 탐색 모드에서 시각적 중복을 해결합니다.

디스플레이 컷아웃 인셋

일부 기기에는 디스플레이 컷아웃이 있습니다. 일반적으로 컷아웃은 화면 상단에 있으며 상태 표시줄에 포함됩니다. 기기 화면이 가로 모드일 때는 잘림 부분이 세로 가장자리에 있을 수 있습니다. 앱이 화면에 표시하는 콘텐츠에 따라 디스플레이 컷아웃을 방지하기 위해 패딩을 구현해야 합니다. 기본적으로 앱은 디스플레이 컷아웃에 그립니다.

예를 들어 많은 앱 화면에는 항목 목록이 표시됩니다. 디스플레이 노출 영역이나 시스템 표시줄로 목록 항목을 가리지 마세요.

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
  val bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
      or WindowInsetsCompat.Type.displayCutout()
  )
  v.updatePadding(
    left = bars.left,
    top = bars.top,
    right = bars.right,
    bottom = bars.bottom,
  )
  WindowInsetsCompat.CONSUMED
}

자바

ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> {
  Insets bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
    | WindowInsetsCompat.Type.displayCutout()
  );
  v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
  return WindowInsetsCompat.CONSUMED;
});

시스템 표시줄 및 디스플레이 노출 영역 유형의 논리적 또는을 사용하여 WindowInsetsCompat 값을 결정합니다.

패딩이 목록 항목과 함께 스크롤되도록 clipToPaddingRecyclerView로 설정합니다. 이렇게 하면 다음 예와 같이 사용자가 스크롤할 때 항목이 시스템 막대 뒤로 이동할 수 있습니다.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

시스템 동작 인셋

시스템 동작 인셋은 시스템 동작이 앱보다 우선 적용되는 창 영역을 나타냅니다. 이러한 영역은 그림 6에서 주황색으로 표시되어 있습니다.

시스템 동작 인셋의 예
그림 6. 시스템 동작 인셋

시스템 표시줄 인셋과 마찬가지로 WindowInsetsCompat.Type.systemGestures()와 함께 getInsets(int)를 사용하여 시스템 동작 인셋이 겹치는 것을 방지할 수 있습니다.

이 인셋을 사용하여 스와이프 가능한 뷰를 가장자리에서 벗어나게 이동하거나 패딩합니다. 일반적인 사용 사례로는 하단 시트, 게임에서의 스와이프, ViewPager2를 사용하여 구현된 캐러셀이 있습니다.

Android 10 이상에서는 시스템 동작 인셋에 홈 동작의 하단 인셋과 뒤로 동작의 왼쪽 및 오른쪽 인셋이 포함됩니다.

시스템 동작 인셋 측정의 예
그림 7. 시스템 동작 인셋 측정값

다음 코드 예는 시스템 동작 인셋을 구현하는 방법을 보여줍니다.

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.updatePadding(insets.left, insets.top, insets.right, insets.bottom)

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    WindowInsetsCompat.CONSUMED
}

자바

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Material 구성요소

많은 뷰 기반 Android Material 구성요소(com.google.android.material){:.external}는 BottomAppBar, BottomNavigationView, NavigationRailView, NavigationView를 비롯하여 인셋을 자동으로 처리합니다.

하지만 AppBarLayout는 인셋을 자동으로 처리하지 않습니다. android:fitsSystemWindows="true"를 추가하여 상단 인셋을 처리합니다.

Compose의 Material 구성요소로 인셋을 처리하는 방법을 알아보세요.

하위 호환 인셋 전달

자식 뷰에 인셋 전달을 중지하고 패딩 오버를 방지하려면 WindowInsetsCompat.CONSUMED 상수를 사용하여 인셋을 사용할 수 있습니다. 그러나 Android 10 (API 수준 29 이하)을 실행하는 기기에서는 WindowInsetsCompat.CONSUMED를 호출한 후 인셋이 형제 요소에 전달되지 않으므로 의도치 않은 시각적 중복이 발생할 수 있습니다.

잘못된 인셋 전달 예시
그림 8. 잘못된 인셋 전달 예시 Android 10 (API 수준 29) 이하에서 ViewGroup 1이 인셋을 사용한 후 인셋이 뷰 형제 요소에 전달되지 않아 TextView 2가 시스템 탐색 메뉴와 겹칩니다. 하지만 Android 11 (API 수준 30) 이상에서는 예상대로 인셋이 상위 뷰에 전달됩니다.

지원되는 모든 Android 버전에서 인셋이 상위 요소에 전달되는지 확인하려면 인셋을 사용하기 전에 ViewGroupCompat#installCompatInsetsDispatch를 사용하세요. ViewGroupCompat#installCompatInsetsDispatchAndroidX Core 및 Core-ktx 1.16.0-alpha01 이상에서 사용할 수 있습니다.

Kotlin

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
val rootView = findViewById(R.id.main)
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView)

자바

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
LinearLayout rootView = findViewById(R.id.main);
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView);
수정된 인셋 전달 예시
그림 9. ViewGroupCompat#installCompatInsetsDispatch를 호출한 후 인셋 전달을 수정했습니다.

몰입형 모드

일부 콘텐츠는 전체 화면으로 시청하는 것이 가장 좋습니다. 이렇게 하면 사용자에게 더 몰입도 높은 환경을 제공할 수 있습니다. WindowInsetsControllerWindowInsetsControllerCompat 라이브러리를 사용하여 몰입형 모드의 시스템 표시줄을 숨길 수 있습니다.

Kotlin

val windowInsetsController =
      WindowCompat.getInsetsController(window, window.decorView)

// Hide the system bars.
windowInsetsController.hide(Type.systemBars())

// Show the system bars.
windowInsetsController.show(Type.systemBars())

자바

Window window = getWindow();
WindowInsetsControllerCompat windowInsetsController =
      WindowCompat.getInsetsController(window, window.getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());

이 기능을 구현하는 방법에 관한 자세한 내용은 몰입형 모드의 시스템 표시줄 숨기기를 참고하세요.

시스템 표시줄 아이콘

enableEdgeToEdge를 호출하면 기기 테마가 변경될 때 시스템 표시줄 아이콘 색상이 업데이트됩니다.

더 넓은 화면으로 전환하는 동안 시스템 표시줄 아이콘 색상이 앱 배경과 대비되도록 수동으로 업데이트해야 할 수 있습니다. 예를 들어 밝은 상태 표시줄 아이콘을 만들려면 다음을 실행합니다.

Kotlin

WindowCompat.getInsetsController(window, window.decorView)
    .isAppearanceLightStatusBars = false

자바

WindowCompat.getInsetsController(window, window.getDecorView())
    .setAppearanceLightStatusBars(false);

시스템 표시줄 보호

앱이 SDK 35 이상을 타겟팅하면 전면이 전체 화면으로 표시됩니다. 시스템 상태 표시줄과 동작 탐색 메뉴는 투명하지만 3버튼 탐색 메뉴는 반투명합니다.

기본 반투명 3버튼 탐색 배경 보호를 삭제하려면 Window.setNavigationBarContrastEnforcedfalse로 설정합니다.

추가 리소스

WindowInsets, 동작 탐색, 인셋 작동 방식에 관한 자세한 내용은 다음 참조를 참고하세요.