Komponent Nawigacja udostępnia język oparty na domenie Kotlin.
który wykorzystuje mechanizm bezpiecznego typu pliku Kotlin
budownicze
, Ten interfejs API umożliwia deklaratywne skomponowanie grafu w kodzie Kotlin, a nie
niż w zasobie XML. Może to być przydatne, jeśli chcesz tworzyć
porusza się dynamicznie. Na przykład aplikacja może pobrać i zapisać w pamięci podręcznej
konfigurację nawigacji z zewnętrznej usługi sieciowej, a następnie użyć jej
aby dynamicznie tworzyć wykres nawigacji w
onCreate()
.
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.8.4" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.4" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Tworzenie wykresu
Oto podstawowy przykład oparty na kluczu Słonecznik
Do tego celu
mamy na przykład dwa 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
.
Hosting grafu nawigacyjnego DSL Kotlin
Aby utworzyć wykres nawigacji dla aplikacji, musisz mieć miejsce do przechowywania
wykres. W tym przykładzie użyto fragmentów, więc 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.
Działanie w pliku XML wiąże identyfikator miejsca docelowego z co najmniej jednym argumentem. Jednak w przypadku korzystania z nawigacji DSL trasa może zawierać argumenty trasę. 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 do wykresu
Wykresy nawigacyjne oparte na formacie XML są analizowane jako część
procesu tworzenia Androida. Dla każdego elementu id
tworzona jest stała liczbowa.
zdefiniowany na wykresie. Te statyczne identyfikatory wygenerowane podczas kompilacji nie są
dostępne przy tworzeniu wykresu nawigacji w czasie działania, dzięki czemu
korzysta z funkcji serializowalności
zamiast
Identyfikatory. Każda trasa jest reprezentowana przez inny typ.
Gdy rozmawiamy z argumentami, są one wbudowane w proces . Dzięki temu masz pewność, że podczas pisania dla argumentów nawigacyjnych.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Tworzenie wykresu za pomocą DSL NavGraphBuilder
Po zdefiniowaniu tras możesz utworzyć wykres 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 zajęcia w usłudze Fragment
, który udostępnia interfejs użytkownika tego miejsca docelowego. Ustawienie ma taki sam skutek jak
ustawianie atrybutu android:name
w zdefiniowanych docelowych miejscach docelowych fragmentów
przy użyciu 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 na potrzeby dodatkowej konfiguracji, takiej jak jak etykieta docelowa, jak również osadzone funkcje kreatora i precyzyjnych linków.
Poruszanie się po wykresie DSL Kotlin
Możesz też przejść z home
do plant_detail
, korzystając z
NavController.navigate()
.
połączenia:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
W narzędziu PlantDetailFragment
można uzyskać argumenty nawigacyjne, uzyskując
bieżącego
NavBackStackEntry
.
i dzwoniąc
toRoute
, aby uzyskać wystąpienie trasy.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Jeśli PlantDetailFragment
używa ViewModel
, uzyskaj wystąpienie trasy za pomocą
SavedStateHandle.toRoute
.
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
W pozostałej części tego przewodnika znajdziesz opis często używanych elementów wykresu nawigacji, miejsc docelowych, i jak ich używać do tworzenia wykresów.
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
activity()
Funkcja DSL przyjmuje parametr typu trasy, ale nie ma parametru
wszystkich implementujących klas aktywności. 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
skonfigurować wykres. Prawidłowe elementy to między innymi inne miejsca docelowe i argument niestandardowy
typów precyzyjnych linków oraz etykietę opisową
miejsce docelowe.
Ta etykieta może być przydatna do powiązania grafu nawigacyjnego z komponentami interfejsu 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óry nie obsługuje bezpośrednio DSL Kotlin, możesz dodać te miejsca docelowe do
za pomocą lustrzanek DSL Kotlin,
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ć jednoargumentowego operatora plus, aby dodać nowe miejsce docelowe bezpośrednio na wykres:
// 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. Mogą to być zdefiniowane w taki sam sposób jak dla każdej klasy Kotlin. Wymagane argumenty to zdefiniowane jako typy niedopuszczające wartości null, a opcjonalne argumenty są zdefiniowane domyślnie .
Bazowy mechanizm reprezentowania tras i ich argumentów to ciąg znaków
oparte na danych. 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ć serializowalny, czyli powinien mieć
, która konwertuje w pamięci reprezentację wartości argumentu na
String
Serializacja Kotlin
wtyczka
automatycznie generuje metody serializacji dla podstawowego
, gdy
Do obiektu została 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
. Ten
pozwala kontrolować, w jaki sposób Twój typ jest 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
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
Niestandardowy obiekt NavType
może być zapisany w ten sposób:
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 następnie użyć w DSL Kotlin tak jak każdego innego:
fragment<SearchFragment, SearchRoute> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
Podczas nawigowania do miejsca docelowego utwórz instancję trasy:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
Ten parametr można pobrać z trasy w miejscu docelowym:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Precyzyjne linki
Precyzyjne linki można dodawać do każdego miejsca docelowego, tak jak w przypadku witryny opartej na formacie XML. wykres nawigacyjny. Wszystkie procedury opisane w sekcji Tworzenie precyzyjnego linku dotyczące miejsca docelowego. tworzenia precyzyjnego linku za pomocą lustrzanek DSL Kotlin.
Podczas tworzenia niejawnego precyzyjnego linku
nie masz jednak zasobu nawigacji XML, który można przeanalizować
<deepLink>
elementów. Dlatego nie można polegać na umieszczeniu <nav-graph>
element w pliku AndroidManifest.xml
i musi zamiast tego dodać atrybut intent
ręcznie. Zamiar
Podany filtr powinien pasować do ścieżki podstawowej, działania i typu MIME
precyzyjne linki do 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, a
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.
Ten przykład pozwala utworzyć identyfikator URI precyzyjnego linku dla 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 zapytanie
parametry (przykład:
?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 ten 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 ograniczeń co do 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, która jest przechowywana w tym miejscu docelowym.
Ograniczenia
Wtyczka Safe Args
niekompatybilny z DSL Kotlin, ponieważ wtyczka szuka plików zasobów XML w celu
wygenerować zajęcia Directions
i Arguments
.