Komponent Nawigacja udostępnia język oparty na domenie Kotlin.
która bazuje na technologii Kotlin bezpiecznej dla typu
budownicze
, Ten interfejs API umożliwia deklaratywnie tworzenie grafu w kodzie Kotlina, a nie w zasobach XML. Może to być przydatne, jeśli chcesz tworzyć
porusza się dynamicznie. Aplikacja może na przykład pobierać i przechowywać w pamięci podręcznej konfigurację nawigacji z zewnętrznej usługi internetowej, a następnie używać tej konfiguracji do dynamicznego tworzenia grafu nawigacji w funkcji onCreate()
aktywności.
Zależności
Aby używać DSL Kotlin z fragmentami, dodaj następującą zależność do funkcji
Plik build.gradle
:
Groovy
dependencies { def nav_version = "2.9.3" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.9.3" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Tworzenie wykresu
Oto podstawowy przykład oparty na aplikacji Sunflower. W tym przykładzie mamy 2 miejsca docelowe: home
i plant_detail
. home
miejsce docelowe jest obecne przy pierwszym uruchomieniu aplikacji przez użytkownika. To miejsce docelowe
wyświetla listę roślin z ogrodu użytkownika. Gdy użytkownik wybierze jedną z tych opcji:
rośliny, aplikacja przejdzie do miejsca docelowego plant_detail
.
Rys. 1 przedstawia te miejsca docelowe wraz z argumentami wymaganymi przez
miejsce docelowe plant_detail
i działanie to_plant_detail
używane przez aplikację
aby przejść z home
do plant_detail
.

home
i plant_detail
, a także działanie, które je łączy.Hostowanie grafu nawigacyjnego Kotlin DSL
Aby utworzyć wykres nawigacyjny aplikacji, musisz mieć miejsce do przechowywania
wykres. W tym przykładzie użyto fragmentów, dlatego wykres jest przechowywany w
NavHostFragment
wewnątrz
FragmentContainerView
:
<!-- activity_garden.xml -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true" />
</FrameLayout>
Zwróć uwagę, że w tym przykładzie atrybut app:navGraph
nie jest ustawiony. Wykres
nie jest zdefiniowany jako zasób w
folderu res/navigation
, więc należy go ustawić jako część folderu onCreate()
w trakcie aktywności.
W kodzie XML działanie łączy identyfikator miejsca docelowego z co najmniej 1 argumentem. Jednak podczas korzystania z DSL nawigacji trasa może zawierać argumenty jako część trasy. Oznacza to, że przy korzystaniu z DSL nie ma koncepcji działań.
Następnym krokiem jest zdefiniowanie tras, których będziesz używać do definiowania wykres.
Tworzenie tras na wykresie
Grafiki nawigacji w formacie XML są analizowane w ramach procesu kompilacji Androida. Dla każdego elementu id
tworzona jest stała liczbowa.
zdefiniowany na wykresie. Te identyfikatory statyczne generowane w czasie kompilacji nie są dostępne podczas tworzenia grafu nawigacji w czasie wykonywania, dlatego w jego przypadku język programowania DSL do nawigacji używa typów serializowanych zamiast identyfikatorów. Każda trasa ma swój unikalny typ.
Gdy rozmawiamy z argumentami, są one wbudowane w proces . Dzięki temu masz pewność, że argumenty nawigacji są bezpieczne.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Tworzenie grafu za pomocą DSL NavGraphBuilder
Po zdefiniowaniu tras możesz utworzyć graf nawigacji.
val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
startDestination = Home
) {
fragment<HomeFragment, Home> {
label = resources.getString(R.string.home_title)
}
fragment<PlantDetailFragment, PlantDetail> {
label = resources.getString(R.string.plant_detail_title)
}
}
W tym przykładzie 2 miejsca docelowe fragmentów są zdefiniowane za pomocą atrybutu
fragment()
Funkcja konstruktora DSL. Ta funkcja wymaga dwóch typów
,
Najpierw klasa Fragment
, która zapewnia interfejs użytkownika dla tego miejsca docelowego. Ustawienie tej opcji ma taki sam skutek jak ustawienie atrybutu android:name
w miejscach docelowych fragmentów zdefiniowanych za pomocą kodu XML.
Po drugie, trasa. Musi to być serializowalny typ, który rozciąga się od Any
. it
powinien zawierać wszelkie argumenty nawigacyjne używane przez to miejsce docelowe,
i ich rodzajach.
Funkcja ta akceptuje też opcjonalną funkcję Lambda do dodatkowej konfiguracji, np. etykiety docelowej, a także osadzone funkcje kreatora do niestandardowych argumentów i linków bezpośrednich.
Poruszanie się po diagramie DSL w Kotlinie
Na koniec możesz przejść z home
do plant_detail
za pomocą NavController.navigate()
:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
W PlantDetailFragment
możesz uzyskać argumenty nawigacji, uzyskując bieżący obiekt NavBackStackEntry
i wywołując na nim metodę toRoute
, aby uzyskać instancję trasy.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Jeśli aplikacja PlantDetailFragment
używa modułu ViewModel
, pobierz instancję trasy za pomocą funkcji SavedStateHandle.toRoute
.
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
W dalszej części tego przewodnika opisujemy typowe elementy grafu nawigacyjnego, czyli miejsca docelowe, oraz sposób ich wykorzystania podczas tworzenia grafu.
Miejsca docelowe
Kotlin DSL ma wbudowaną obsługę trzech typów miejsc docelowych:
Fragment
, Activity
i NavGraph
miejsca docelowe, z których każde ma własne
wbudowana funkcja rozszerzenia dostępna do tworzenia i konfigurowania
miejsce docelowe.
Miejsca docelowe fragmentów kodu
fragment()
Funkcję DSL można zdefiniować za pomocą klasy fragmentu dla interfejsu użytkownika i funkcji
typ trasy użyty do jednoznacznego wskazania miejsca docelowego z dodanym parametrem lambda
gdzie można wprowadzić dodatkową konfigurację, zgodnie z opisem w sekcji Nawigacja
z wykresem Kotlin DSL.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
Miejsce docelowe aktywności
Funkcja DSL activity()
przyjmuje parametr typu dla trasy, ale nie jest parametryzowana pod kątem żadnej klasy implementującej aktywność. Zamiast tego możesz ustawić opcjonalny activityClass
w
lambda na końcu. Dzięki tej elastyczności możesz zdefiniować miejsce docelowe aktywności
działania, które należy rozpocząć za pomocą domyślnego
intencja, gdzie jawny
nie miałyby sensu. Podobnie jak w przypadku miejsc docelowych fragmentów, możesz też
skonfigurować etykietę,
niestandardowe argumenty i precyzyjne linki.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
Miejsce docelowe wykresu nawigacyjnego
navigation()
Za pomocą funkcji DSL można utworzyć zagnieżdżoną nawigację
wykres. Ta funkcja przyjmuje typ
trasy, którą należy przypisać do tego wykresu. Przyjmuje też 2 argumenty:
trasę początkowego miejsca docelowego wykresu, a parametr lambda pozwoli kontynuować
skonfigurować wykres. Dozwolone elementy to inne miejsca docelowe, niestandardowe typy argumentów, precyzyjne linki i etykieta opisowa miejsca docelowego.
Ta etykieta może być przydatna do powiązania grafu nawigacji z komponentami interfejsu użytkownika za pomocą NavigationUI
.
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
Obsługa niestandardowych miejsc docelowych
Jeśli używasz nowego typu miejsca docelowego, które nie obsługuje bezpośrednio Kotlin DSL, możesz dodać te miejsca docelowe do Kotlin DSL za pomocą addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
Możesz też użyć operatora jednoargumentowego plusa, aby dodać nowo utworzone miejsce docelowe bezpośrednio do grafu:
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
Podawanie argumentów miejsca docelowego
Argumenty miejsca docelowego można zdefiniować jako część klasy trasy. Można je zdefiniować w taki sam sposób jak dowolną klasę Kotlina. Wymagane argumenty są zdefiniowane jako typy, które nie mogą być puste, a opcjonalne argumenty są zdefiniowane z wartościami domyślnymi.
Mechanizm reprezentowania tras i ich argumentów opiera się na ciągach znaków. Używanie ciągów tekstowych do modelowania tras umożliwia przechowywanie stanu nawigacji
przywrócone z dysku podczas konfiguracji
zmian i procesu inicjowanego przez system
śmierć. Z tego powodu każdy argument nawigacji musi być serializowany, czyli musi mieć metodę, która konwertuje reprezentację wartości argumentu w pamięci na String
.
Wtyczka do serializacji w Kotlinie automatycznie generuje metody serializacji dla podstawowych typów, gdy do obiektu zostanie dodana adnotacja @Serializable
.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Podawanie typów niestandardowych
W przypadku niestandardowych typów argumentów musisz podać niestandardową klasę NavType
. Dzięki temu możesz dokładnie określić, jak Twój typ ma być analizowany z trasy lub precyzyjnego linku.
Na przykład trasa używana do zdefiniowania ekranu wyszukiwania może zawierać klasę, która reprezentuje parametry wyszukiwania:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
@Parcelize
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
Niestandardowa wartość NavType
może mieć postać:
val SearchParametersType = object : NavType<SearchParameters>(
isNullableAllowed = false
) {
override fun put(bundle: Bundle, key: String, value: SearchParameters) {
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): SearchParameters {
return bundle.getParcelable(key) as SearchParameters
}
override fun serializeAsValue(value: SearchParameters): String {
// Serialized values must always be Uri encoded
return Uri.encode(Json.encodeToString(value))
}
override fun parseValue(value: String): SearchParameters {
// Navigation takes care of decoding the string
// before passing it to parseValue()
return Json.decodeFromString<SearchParameters>(value)
}
}
Możesz go potem używać w Kotlin DSL tak jak każdego innego typu:
fragment<SearchFragment, SearchRoute>(
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
) {
label = getString(R.string.plant_search_title)
}
Podczas nawigacji do miejsca docelowego utwórz instancję trasy:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
Parametr można uzyskać z trasy w miejscu docelowym:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Precyzyjne linki
Precyzyjne linki można dodawać do dowolnego miejsca docelowego, tak jak w przypadku XML-owego grafu nawigacyjnego. Do procesu tworzenia precyzyjnego linku za pomocą Kotlin DSL mają zastosowanie wszystkie procedury zdefiniowane w sekcji Tworzenie precyzyjnego linku do miejsca docelowego.
Podczas tworzenia domyślnego precyzyjnego linku nie masz jednak zasobu nawigacji XML, który można by przeanalizować pod kątem elementów <deepLink>
. Dlatego nie można polegać na umieszczeniu <nav-graph>
element w pliku AndroidManifest.xml
i musi zamiast tego dodać atrybut intent
ręcznie dodawać filtry do aktywności. Podany przez Ciebie filtr intencji powinien pasować do ścieżki podstawowej, działania i typu MIME precyzyjnych linków w aplikacji.
Precyzyjne linki są dodawane do miejsca docelowego przez wywołanie w nim funkcji deepLink
lambda dla miejsca docelowego. Akceptuje on trasę jako typ z parametrami,
basePath
jako ścieżki podstawowej adresu URL używanego na potrzeby precyzyjnego linku.
Możesz również dodać działanie i typ MIME za pomocą funkcji
deepLinkBuilder
lambda na końcu.
W tym przykładzie tworzymy identyfikator URI precyzyjnego linku do miejsca docelowego Home
.
@Serializable data object Home
fragment<HomeFragment, Home>{
deepLink<Home>(basePath = "www.example.com/home"){
// Optionally, specify the action and/or mime type that this destination
// supports
action = "android.intent.action.MY_ACTION"
mimeType = "image/*"
}
}
Format identyfikatora URI
Format identyfikatora URI precyzyjnego linku jest generowany automatycznie na podstawie pól trasy przy użyciu tych reguł:
- Wymagane parametry są dodawane jako parametry ścieżki (przykład:
/{id}
). - Parametry z wartością domyślną (parametry opcjonalne) są dołączane jako parametry zapytania (np.
?name={name}
). - Kolekcje są dodawane jako parametry zapytania (przykład:
?items={value1}&items={value2}
). - Kolejność parametrów odpowiada kolejności pól na trasie
Na przykład taki typ trasy:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
ma wygenerowany format URI:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
Nie ma limitu liczby precyzyjnych linków, które możesz dodać. Za każdym razem, gdy do kogoś dzwonisz
deepLink()
nowy precyzyjny link zostanie dołączony do listy prowadzonej w przypadku tego miejsca docelowego.
Ograniczenia
Wtyczka Safe Args
niekompatybilny z DSL Kotlin, ponieważ wtyczka szuka plików zasobów XML w celu
do wygenerowania klas Directions
i Arguments
.