기본사항 이해 및 구현

탐색은 사용자가 앱을 이동하는 방식을 나타냅니다. 사용자는 일반적으로 UI 요소를 탭하거나 클릭하여 상호작용하며 앱은 새 콘텐츠를 표시하여 응답합니다. 사용자가 이전 콘텐츠로 돌아가려면 뒤로 동작을 사용하거나 뒤로 버튼을 탭합니다.

탐색 상태 모델링

이 동작을 모델링하는 편리한 방법은 콘텐츠 스택을 사용하는 것입니다. 사용자가 새 콘텐츠로 이동하면 스택의 맨 위에 푸시됩니다. 사용자가 해당 콘텐츠에서 뒤로 이동하면 스택에서 콘텐츠가 팝되고 이전 콘텐츠가 표시됩니다. 탐색 용어로 이 스택은 사용자가 되돌아갈 수 있는 콘텐츠를 나타내므로 일반적으로 뒤로 스택이라고 합니다.

소프트웨어 키보드 작업 버튼 (체크표시 아이콘)이 빨간색으로 표시되어 있습니다.
그림 1. 사용자 탐색 이벤트에 따라 뒤로 스택이 어떻게 변경되는지 보여주는 다이어그램

백 스택 만들기

탐색 3에서는 뒤로 스택에 실제로 콘텐츠가 포함되지 않습니다. 대신 라고 하는 콘텐츠 참조가 포함됩니다. 키는 어떤 유형이든 될 수 있지만 일반적으로 직렬화 가능한 간단한 데이터 클래스입니다. 콘텐츠 대신 참조를 사용하면 다음과 같은 이점이 있습니다.

  • 키를 백 스택에 푸시하여 간단하게 탐색할 수 있습니다.
  • 키가 직렬화 가능한 한 백 스택을 영구 저장소에 저장할 수 있으므로 구성 변경 및 프로세스 종료 후에도 유지할 수 있습니다. 이는 사용자가 앱을 나갔다가 나중에 다시 돌아와서 중단한 지점부터 동일한 콘텐츠가 표시되기를 기대하기 때문에 중요합니다. 자세한 내용은 뒤로 스택 저장을 참고하세요.

Navigation 3 API의 핵심 개념은 뒤로 스택을 소유한다는 것입니다. 라이브러리는 다음을 실행합니다.

  • 백 스택이 스냅샷 상태 백업 List<T>이어야 합니다. 여기서 T은 백 스택 keys의 유형입니다. Any를 사용하거나 더 강력한 유형의 자체 키를 제공할 수 있습니다. '푸시' 또는 '팝'이라는 용어가 표시되면 기본 구현은 목록 끝에 항목을 추가하거나 삭제하는 것입니다.
  • 백 스택을 관찰하고 NavDisplay를 사용하여 UI에 상태를 반영합니다.

다음 예에서는 키와 백 스택을 만들고 사용자 탐색 이벤트에 응답하여 백 스택을 수정하는 방법을 보여줍니다.

// Define keys that will identify content
data object ProductList
data class ProductDetail(val id: String)

@Composable
fun MyApp() {

    // Create a back stack, specifying the key the app should start with
    val backStack = remember { mutableStateListOf<Any>(ProductList) }

    // Supply your back stack to a NavDisplay so it can reflect changes in the UI
    // ...more on this below...

    // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state
    backStack.add(ProductDetail(id = "ABC"))

    // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state
    backStack.removeLastOrNull()
}

콘텐츠 키 확인

콘텐츠는 컴포저블 함수가 포함된 클래스인 NavEntry를 사용하여 Navigation 3에서 모델링됩니다. 대상을 나타냅니다. 즉, 사용자가 이어서 이동하고 뒤로 이동할 수 있는 단일 콘텐츠입니다.

NavEntry에는 콘텐츠에 관한 정보인 메타데이터도 포함될 수 있습니다. 이 메타데이터는 NavDisplay와 같은 컨테이너 객체에서 읽을 수 있으므로 NavEntry의 콘텐츠를 표시하는 방법을 결정하는 데 도움이 됩니다. 예를 들어 메타데이터를 사용하여 특정 NavEntry의 기본 애니메이션을 재정의할 수 있습니다. NavEntry metadataString 키를 Any 값에 매핑하여 다양한 데이터 저장소를 제공합니다.

keyNavEntry로 변환하려면 entryProvider를 만듭니다. key를 수락하고 해당 keyNavEntry를 반환하는 함수입니다. 일반적으로 NavDisplay를 만들 때 람다 매개변수로 정의됩니다.

entryProvider를 만드는 방법에는 두 가지가 있습니다. 람다 함수를 직접 만들거나 entryProvider DSL을 사용하는 것입니다.

entryProvider 함수 직접 만들기

일반적으로 when 문을 사용하여 entryProvider 함수를 만들고 각 키에 대한 브랜치를 사용합니다.

entryProvider = { key ->
    when (key) {
        is ProductList -> NavEntry(key) { Text("Product List") }
        is ProductDetail -> NavEntry(
            key,
            metadata = mapOf("extraDataKey" to "extraDataValue")
        ) { Text("Product ${key.id} ") }

        else -> {
            NavEntry(Unit) { Text(text = "Invalid Key: $it") }
        }
    }
}

entryProvider DSL 사용

entryProvider DSL은 각 키 유형에 대해 테스트할 필요가 없으므로 람다 함수를 단순화하고 각 키 유형에 대해 NavEntry를 구성할 수 있습니다. 이를 위해 entryProvider 빌더 함수를 사용합니다. 키를 찾을 수 없는 경우의 기본 대체 동작 (오류 발생)도 포함되어 있습니다.

entryProvider = entryProvider {
    entry<ProductList> { Text("Product List") }
    entry<ProductDetail>(
        metadata = mapOf("extraDataKey" to "extraDataValue")
    ) { key -> Text("Product ${key.id} ") }
}

스니펫에서 다음 사항에 유의하세요.

  • entry는 지정된 유형 및 컴포저블 콘텐츠로 NavEntry를 정의하는 데 사용됩니다.
  • entrymetadata 매개변수를 사용하여 NavEntry.metadata를 설정합니다.

백 스택 표시

백 스택은 앱의 탐색 상태를 나타냅니다. 백 스택이 변경될 때마다 앱 UI는 새 백 스택 상태를 반영해야 합니다. Navigation 3에서 NavDisplay는 백 스택을 관찰하고 그에 따라 UI를 업데이트합니다. 다음 매개변수를 사용하여 생성합니다.

  • 백 스택 - SnapshotStateList<T> 유형이어야 하며 여기서 T는 백 스택 키의 유형입니다. 관찰 가능한 List이므로 변경될 때 NavDisplay의 리컴포지션을 트리거합니다.
  • 백 스택의 키를 NavEntry로 변환하는 entryProvider입니다.
  • 원하는 경우 onBack 매개변수에 람다를 제공합니다. 사용자가 뒤로 이벤트를 트리거할 때 호출됩니다.

다음 예는 NavDisplay를 만드는 방법을 보여줍니다.

data object Home
data class Product(val id: String)

@Composable
fun NavExample() {

    val backStack = remember { mutableStateListOf<Any>(Home) }

    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeLastOrNull() },
        entryProvider = { key ->
            when (key) {
                is Home -> NavEntry(key) {
                    ContentGreen("Welcome to Nav3") {
                        Button(onClick = {
                            backStack.add(Product("123"))
                        }) {
                            Text("Click to navigate")
                        }
                    }
                }

                is Product -> NavEntry(key) {
                    ContentBlue("Product ${key.id} ")
                }

                else -> NavEntry(Unit) { Text("Unknown route") }
            }
        }
    )
}

기본적으로 NavDisplay는 단일 창 레이아웃에서 백 스택의 최상위 NavEntry를 표시합니다. 다음 녹화 파일은 이 앱이 실행되는 모습을 보여줍니다.

두 대상이 있는 `NavDisplay` 기본 동작
그림 2. 두 대상이 있는 NavDisplay 기본 동작

종합적으로 살펴보기

다음 다이어그램은 탐색 3의 여러 객체 간에 데이터가 흐르는 방식을 보여줍니다.

탐색 3의 다양한 객체 간에 데이터가 흐르는 방식을 시각화한 이미지입니다.
그림 3. 탐색 3에서 데이터가 다양한 객체를 통해 흐르는 방식을 보여주는 다이어그램
  1. 탐색 이벤트가 변경을 시작합니다. 키는 사용자 상호작용에 응답하여 백 스택에 추가되거나 삭제됩니다.

  2. 백 스택 상태 변경이 콘텐츠 검색을 트리거합니다. NavDisplay(백 스택을 렌더링하는 컴포저블)는 백 스택을 관찰합니다. 기본 구성에서는 단일 창 레이아웃에 최상위 백 스택 항목을 표시합니다. 백 스택의 최상위 키가 변경되면 NavDisplay는 이 키를 사용하여 항목 제공업체에 해당 콘텐츠를 요청합니다.

  3. 항목 제공업체가 콘텐츠를 제공합니다. 항목 제공업체는 키를 NavEntry로 확인하는 함수입니다. 항목 제공업체는 NavDisplay에서 키를 수신하면 키와 콘텐츠가 모두 포함된 연결된 NavEntry를 제공합니다.

  4. 콘텐츠가 표시됩니다. NavDisplayNavEntry를 수신하고 콘텐츠를 표시합니다.