목록-세부정보 레이아웃 빌드

목록-세부정보는 하나의 창에 항목 목록을 표시하고 다른 창에 목록에서 선택한 항목의 세부정보를 표시하는 이중 창 레이아웃으로 구성된 UI 패턴입니다.

이 패턴은 대규모 컬렉션의 요소에 관한 심층 정보를 제공하는 애플리케이션(예: 이메일 목록과 각 이메일 메시지의 세부 콘텐츠가 있는 이메일 클라이언트)에 특히 유용합니다. List-detail은 앱 환경설정을 세부정보 창에 각 카테고리의 환경설정이 포함된 카테고리 목록으로 나누는 등 덜 중요한 경로에도 사용할 수 있습니다.

ListDetailPaneScaffold를 사용하여 UI 패턴 구현

ListDetailPaneScaffold는 앱에서 목록 세부정보 패턴의 구현을 간소화하는 컴포저블입니다. 목록 세부정보 스켈레톤은 목록 창, 세부정보 창, 선택적 추가 창 등 최대 3개의 창으로 구성될 수 있습니다. 스캐폴드는 화면 공간 계산을 처리합니다. 충분한 화면 크기를 사용할 수 있으면 세부정보 창이 목록 창과 함께 표시됩니다. 작은 화면 크기에서 Scaffold는 목록 창 또는 세부정보 창을 전체 화면으로 표시하도록 자동으로 전환됩니다.

목록 페이지와 함께 표시되는 세부정보 창
그림 1. 충분한 화면 크기를 사용할 수 있으면 세부정보 창이 목록 창과 함께 표시됩니다.
항목을 선택하면 세부정보 창이 전체 화면을 차지합니다.
그림 2. 화면 크기가 제한된 경우 항목이 선택되었으므로 세부정보 창이 전체 공간을 차지합니다.

종속 항목 선언

ListDetailPaneScaffoldMaterial 3 적응형 레이아웃 라이브러리의 일부입니다.

앱 또는 모듈의 build.gradle 파일에 다음과 같은 관련 종속 항목 세 개를 추가합니다.

Kotlin

implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")

Groovy

implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
  • 적응형: HingeInfoPosture와 같은 하위 수준 구성요소
  • adaptive-layout: ListDetailPaneScaffoldSupportingPaneScaffold와 같은 적응형 레이아웃
  • adaptive-navigation: 창 내부 및 창 간에 탐색하는 컴포저블

기본 사용법

다음과 같이 ListDetailPaneScaffold을 구현합니다.

  1. 선택할 콘텐츠를 나타내는 클래스를 사용합니다. 선택된 목록 항목의 저장 및 복원을 지원하려면 이 클래스가 Parcelable이어야 합니다. kotlin-parcelize 플러그인을 사용하여 코드를 자동으로 생성합니다.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. rememberListDetailPaneScaffoldNavigatorThreePaneScaffoldNavigator를 만들고 BackHandler를 추가합니다. 이 탐색기는 목록, 세부정보, 추가 창 간에 이동하는 데 사용됩니다. 일반 유형을 선언하면 탐색기가 Scaffold의 상태 (즉, MyItem가 표시되는 상태)도 추적합니다. 이 유형은 파티셔널화 가능하므로 탐색기에서 상태를 저장하고 복원하여 구성 변경을 자동으로 처리할 수 있습니다. BackHandler는 시스템 뒤로 동작 또는 버튼을 사용하여 뒤로 이동하는 기능을 지원합니다. ListDetailPaneScaffold의 뒤로 버튼의 예상 동작은 창 크기와 현재 스캐폴드 값에 따라 달라집니다. ListDetailPaneScaffold가 현재 상태로 되돌리기를 지원할 수 있다면 canNavigateBack()true이며 BackHandler를 사용 설정합니다.

    val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. navigator에서 ListDetailPaneScaffold 컴포저블로 scaffoldState를 전달합니다.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. ListDetailPaneScaffold에 목록 창 구현을 제공합니다. AnimatedPane를 사용하여 탐색 중에 기본 창 애니메이션을 적용합니다. 그런 다음 ThreePaneScaffoldNavigator를 사용하여 세부정보 창 ListDetailPaneScaffoldRole.Detail으로 이동하고 전달된 항목을 표시합니다.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. ListDetailPaneScaffold에 세부정보 창 구현을 포함합니다. 탐색이 완료되면 currentDestination에 창에 표시된 콘텐츠를 비롯하여 앱이 이동한 창이 포함됩니다. content 속성은 원래 remember 호출(이 예에서는 MyItem)에 지정된 것과 동일한 유형이므로 표시해야 하는 데이터의 속성에도 액세스할 수 있습니다.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

위 단계를 구현하면 코드가 다음과 같이 표시됩니다.

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)