ナビゲーション コードをカプセル化する

Kotlin DSL を使用してグラフを作成する場合、デスティネーションと 1 つのファイルに含まれるナビゲーション イベントを維持するのが難しい場合があります。これは、 複数の独立した特徴がある場合は特にそうです

宛先の抽出

リンク先を NavGraphBuilder 拡張機能に移行する 使用できます。それらを定義するルートの近くに住む必要があり、 表示画面。たとえば、次のアプリレベルのコードについて考えてみましょう。 これは、連絡先のリストを表示するデスティネーションを作成します。

// MyApp.kt

@Serializable
object Contacts

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
  }
}

ナビゲーション固有のコードを別のファイルに移動する必要があります。

// ContactsNavigation.kt

@Serializable
object Contacts

fun NavGraphBuilder.contactsDestination() {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
}

// MyApp.kt

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination()
  }
}

ルートとデスティネーションの定義がメインアプリから分離され、 個別に更新できますメインアプリは 1 つの できます。この例では、 NavGraphBuilder.contactsDestination()

NavGraphBuilder 拡張関数は、ステートレス 画面レベルのコンポーズ可能な関数と Navigation 固有のロジックがあります。このレイヤは、 状態の発生元とイベントの処理方法も定義します。

次のスニペットでは、新しいデスティネーションを導入して連絡先の 既存の連絡先リストの宛先を更新して 連絡先の詳細を表示する

独自のモジュールに internal できる一般的な画面セットを以下に示します。 他のモジュールがそれにアクセスできないようにすることができます。

// ContactScreens.kt

// Displays a list of contacts
@Composable
internal fun ContactsScreen(
  uiState: ContactsUiState,
  onNavigateToContactDetails: (contactId: String) -> Unit
) { ... }

// Displays the details for an individual contact
@Composable
internal fun ContactDetailsScreen(contact: ContactDetails) { ... }

デスティネーションを作成する

次の NavGraphBuilder 拡張関数は、デスティネーションを作成します。 ContactsScreen コンポーザブルが表示されます。また、オンプレミス ネットワークと ViewModel を使って、画面の UI 状態を提供し、 画面関連のビジネス ロジックです。

連絡先情報のデスティネーションへの移動などのナビゲーション イベントは、 ViewModel で処理されず、呼び出し元に公開されます。

// ContactsNavigation.kt

@Serializable
object Contacts

// Adds contacts destination to `this` NavGraphBuilder
fun NavGraphBuilder.contactsDestination(
  // Navigation events are exposed to the caller to be handled at a higher level
  onNavigateToContactDetails: (contactId: String) -> Unit
) {
  composable<Contacts> {
    // The ViewModel as a screen level state holder produces the screen
    // UI state and handles business logic for the ConversationScreen
    val viewModel: ContactsViewModel = hiltViewModel()
    val uiState = viewModel.uiState.collectAsStateWithLifecycle()
    ContactsScreen(
      uiState,
      onNavigateToContactDetails
    )
  }
}

同じ方法で、表示するデータを表示するデスティネーションを作成できます。 ContactDetailsScreen。この例では、UI の状態を Pod から取得する代わりに、 NavBackStackEntry から直接取得できます。

// ContactsNavigation.kt

@Serializable
internal data class ContactDetails(val id: String)

fun NavGraphBuilder.contactDetailsScreen() {
  composable<ContactDetails> { navBackStackEntry ->
    ContactDetailsScreen(contact = navBackStackEntry.toRoute())
  }
}

ナビゲーション イベントをカプセル化する

デスティネーションをカプセル化するのと同じように、デスティネーションを 使用してルートタイプを不必要に公開しないようにできます。手順 NavController で拡張関数を作成する。

// ContactsNavigation.kt

fun NavController.navigateToContactDetails(id: String) {
  navigate(route = ContactDetails(id = id))
}

まとめ

連絡先を表示するナビゲーション コードが ナビゲーション グラフを使用します。アプリは次のことを行う必要があります。

  • NavGraphBuilder 拡張関数を呼び出してデスティネーションを作成する
  • NavController 拡張関数を呼び出して、これらのデスティネーションを接続します ナビゲーション イベント
// MyApp.kt

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination(onNavigateToContactDetails = { contactId ->
        navController.navigateToContactDetails(id = contactId)
     })
     contactDetailsDestination()
  }
}

まとめ

  • 関連する画面セットのナビゲーション コードをカプセル化します。 別のファイルに
  • NavGraphBuilder で拡張関数を作成してデスティネーションを公開する
  • NavController の拡張関数を作成してナビゲーション イベントを公開する
  • internal を使用して画面とルートタイプを非公開にする