Как преобразовать навигационное приложение Jetpack Compose для использования библиотеки Compose Destinations, чтобы избавиться от шаблонного кода?
В моем предыдущем посте я создал очень простую Jetpack Compose Navigation и использовал герметичный класс NavRoute, чтобы избежать жесткого кодирования строк в нескольких местах.
Однако лучшим решением может быть просто использование этой потрясающей библиотеки Compose Destinations! Давайте посмотрим, как мы можем преобразовать это приложение для использования этой библиотеки.
- Настройка build.gradle (уровень модуля)
- 1. Добавить плагин KSP
- 2. Добавить сгенерированный путь KSP
- 3. Добавить зависимость назначения композиции
- Построение навигационного графа
- 1. Аннотировать экраны с помощью @Destination
- 2. Аннотируйте начальный экран с помощью @RootNavGraph(start = true)
- 3. Замените NavHostController на DestinationsNavigator.
- 4. Вызовите DestinationsNavHost() в главном композитном экране.
- 5. Использование EmptyDestinationsNavigator в @Preview
- Заключение
- Исходный код
- См. также
Настройка build.gradle (уровень модуля)
1. Добавить плагин KSP
Добавьте плагин com.google.devtools.ksp
.
plugins {
...
id 'com.google.devtools.ksp' version '1.6.10-1.0.2'
}
2. Добавить сгенерированный путь KSP
Добавьте сгенерированный путь KSP внутри блока android
.
android {
...
applicationVariants.all { variant ->
kotlin.sourceSets {
getByName(variant.name) {
kotlin.srcDir("build/generated/ksp/${variant.name}/kotlin")
}
}
}
}
3. Добавить зависимость назначения композиции
dependencies {
...
implementation 'io.github.raamcosta.compose-destinations:core:1.5.1-beta'
ksp 'io.github.raamcosta.compose-destinations:ksp:1.5.1-beta'
}
Построение навигационного графа
Существующий код, связанный с навигационным графом (т.е. BuildNavGraph()
и NavRoute
), может быть полностью удален и заменен аннотациями Compose Destinations.
1. Аннотировать экраны с помощью @Destination
Аннотируйте все составные экраны с помощью @Destination
.
@Destination
@Composable
fun LoginScreen(
...
) {
...
@Destination
@Composable
fun HomeScreen(
...
) {
...
@Destination
@Composable
fun ProfileScreen(
...
) {
...
@Destination
@Composable
fun SearchScreen(
...
) {
...
2. Аннотируйте начальный экран с помощью @RootNavGraph(start = true)
@RootNavGraph(start = true)
@Destination
@Composable
fun LoginScreen(
...
)
...
После аннотирования композитного экрана обязательно пересоберите проект, чтобы весь необходимый генерируемый код был сгенерирован.
3. Замените NavHostController
на DestinationsNavigator
.
В оригинальном композитном экране входа в систему есть такой обратный вызов navigateToHome
.
fun LoginScreen(
navigateToHome: () -> Unit
) {
...
}
Теперь его можно заменить параметром DestinationsNavigator
.
fun LoginScreen(
navigator: DestinationsNavigator
) {
...
}
Для навигации в оригинальной реализации используется NavHostController
.
navController.navigate(NavRoute.Home.path)
и теперь заменен на DestinationsNavigator
.
navigator.navigate(HomeScreenDestination)
HomeScreenDestination
— это сгенерированный код.
Некоторые другие примеры преобразования ниже
// #1 - popBackStack()
// convert NavHostController
navController.popBackStack()
// to DestinationsNavigator
navigator.popBackStack()
// #2 - navigate with arguments
// convert NavHostController
navController.navigate(NavRoute.Profile.withArgs(id.toString(), showDetails.toString()))
// to DestinationsNavigator
navigator.navigate(ProfileScreenDestination(7, true))
// #3 - popUpTo()
// convert NavHostController
navController.navigate(NavRoute.Login.path) {
popUpTo(NavRoute.Login.path) {inclusive = true}
}
// to DestinationsNavigator
navigator.navigate(LoginScreenDestination) {
popUpTo(LoginScreenDestination.route) {inclusive = true}
}
Как вы можете видеть,
DestinationsNavigator
по сути является оберткой дляNavHostController
, что значительно упрощает работу.
4. Вызовите DestinationsNavHost()
в главном композитном экране.
Замените BuildNavGraph()
.
@Composable
private fun MainScreen() {
SimpleNavComposeAppTheme {
val navController = rememberNavController()
BuildNavGraph(navController)
}
}
на DestinationsNavHost()
@Composable
private fun MainScreen() {
SimpleNavComposeAppTheme {
DestinationsNavHost(navGraph = NavGraphs.root)
}
}
5. Использование EmptyDestinationsNavigator
в @Preview
Благодаря автору этой библиотеки, Рафаэлю Коста, я узнал, что могу использовать EmptyDestinationsNavigator
в качестве реализации null и использовать его для @preview
вместо передачи null
.
Вместо передачи navigator = null
, я могу передать navigator = EmptyDestinationsNavigator
.
@Preview(showBackground = true)
@Composable
private fun DefaultPreview() {
SimpleNavComposeAppTheme(useSystemUiController = false) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
HomeScreen(navigator = EmptyDestinationsNavigator)
}
}
}
Делая это, мне не нужно объявлять navigator: DestinationsNavigator?
нулевой параметр переменной в композитной функции.
Готово!
Заключение
Эта библиотека просто великолепна! Она избавляет от многих кодовых шаблонов. Единственное, что я хотел бы, это то, что мне не нужно настраивать как в Шаге 1 — Добавить KSP Plugin и Шаге 2 — Добавить сгенерированный KSP Path выше, но, возможно, это технически не осуществимо.
Исходный код
- Дифференциал преобразования здесь.
- Репозиторий GitHub: Demo_SimpleNavigationCompose (ветка compose_destinations)
См. также
- Пример простой навигации Jetpack Compose
Первоначально опубликовано на https://vtsen.hashnode.dev.