Komponent Nawigacja udostępnia język oparty na domenie Kotlin.
DSL, który opiera się na kodzie Kotlina
kreatorów bezpiecznych typu.
Ten interfejs API umożliwia deklaratycyjne skomponowanie grafu w kodzie Kotlin,
a nie wewnątrz zasobu XML. Może to być przydatne, jeśli chcesz tworzyć
do dynamicznego nawigacji w aplikacji. Na przykład aplikacja może pobierać oraz
zapisać w pamięci podręcznej konfigurację nawigacji z zewnętrznej usługi sieciowej, a następnie użyć
aby dynamicznie tworzyć wykres nawigacji w
onCreate()
.
Zależności
Aby używać DSL Kotlin, dodaj następującą zależność do
Plik build.gradle
:
Odlotowe
dependencies { def nav_version = "2.7.7" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.7.7" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Tworzenie wykresu
Zacznijmy od podstawowego przykładu opartego na
Aplikacja 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
.
![Aplikacja Sunflower ma 2 miejsca docelowe wraz z działaniem, które
ich łączy.](https://developer.android.google.cn/static/images/guide/navigation/navigation-kotlin-dsl-1.png?authuser=19&hl=pl)
home
i plant_detail
oraz działanie, które
ich łącząca.Hosting grafu nawigacyjnego DSL Kotlin
Aby utworzyć wykres nawigacyjny 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
zasobu w
res/navigation
, więc należy ustawić go 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 drogi. Oznacza to, że przy korzystaniu z DSL nie ma koncepcji działań.
Następnym krokiem jest określenie kilku stałych, których użyjesz do określenia wykres.
Utwórz stałe do wykresu
Wykresy nawigacyjne oparte na formacie XML
są analizowane w ramach procesu kompilacji Androida. Zostanie utworzona stała liczbowa
dla każdego atrybutu id
zdefiniowanego na wykresie. Te statyczne wartości wygenerowane podczas kompilacji
Identyfikatory nie są dostępne podczas tworzenia wykresu nawigacji w czasie działania, więc
Nawigacja DSL używa ciągów tras zamiast identyfikatorów. Każda trasa jest reprezentowana przez
unikalny ciąg znaków. Warto zdefiniować je jako stałe, aby zmniejszać
ryzyko popełnienia literówek.
Gdy chodzi o argumenty, są to wbudowanej w ciąg znaków trasy. Wbudowanie takiej logiki w trasę może ponownie zmniejszyć ryzyko z błędami literowymi.
object nav_routes {
const val home = "home"
const val plant_detail = "plant_detail"
}
object nav_arguments {
const val plant_id = "plant_id"
const val plant_name = "plant_name"
}
Tworzenie wykresu za pomocą DSL NavGraphBuilder
Po zdefiniowaniu stałych możesz utworzyć nawigację wykres.
val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
startDestination = nav_routes.home
) {
fragment<HomeFragment>(nav_routes.home) {
label = resources.getString(R.string.home_title)
}
fragment<PlantDetailFragment>("${nav_routes.plant_detail}/{${nav_arguments.plant_id}}") {
label = resources.getString(R.string.plant_detail_title)
argument(nav_arguments.plant_id) {
type = NavType.StringType
}
}
}
W tym przykładzie na końcu funkcja lambda określa 2 miejsca docelowe fragmentów za pomocą parametru
fragment()
Funkcja konstruktora DSL. Ta funkcja wymaga ciągu trasy dla miejsca docelowego
uzyskane ze stałych. Funkcja akceptuje też opcjonalne wartości
lambda na potrzeby dodatkowej konfiguracji, np. etykiety miejsca docelowego,
z wbudowanymi funkcjami kreatora na potrzeby argumentów i precyzyjnych linków.
Zajęcia Fragment
, które
zarządza interfejsem każdego miejsca docelowego jest przekazywany jako typ z parametrami
nawiasy kątowe (<>
). Efekt jest taki sam jak w przypadku ustawienia android:name
w miejscach docelowych fragmentów zdefiniowanych za pomocą kodu XML.
Poruszanie się po wykresie DSL Kotlin
Możesz też nawigować z home
do plant_detail
, korzystając ze standardowej trasy
NavController.navigation()
połączenia:
private fun navigateToPlant(plantId: String) {
findNavController().navigate("${nav_routes.plant_detail}/$plantId")
}
W funkcji PlantDetailFragment
możesz uzyskać podaną wartość argumentu
w tym przykładzie:
val plantId: String? = arguments?.getString(nav_arguments.plant_id)
Szczegółowe informacje na temat podawania argumentów podczas nawigacji można znaleźć w podawanie argumentów miejsca docelowego.
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 dostosować do parametrów implementacji klasy fragmentu i pobierać
unikalny ciąg trasy, który ma zostać przypisany do tego miejsca docelowego, po którym następuje znak lambda, gdzie
możesz podać dodatkową konfigurację, zgodnie z
Nawigacja przy użyciu wykresu DSL Kotlin
.
fragment<FragmentDestination>(nav_routes.route_name) {
label = getString(R.string.fragment_title)
// arguments, deepLinks
}
Miejsce docelowe aktywności
activity()
Funkcja DSL wykorzystuje unikalny ciąg trasy do przypisania do tego miejsca docelowego, ale jest
nie ma parametru przypisanego do żadnej implementowanej klasy aktywności. Zamiast tego musisz ustawić
opcjonalnie activityClass
w parametrze lambda na końcu. Ta elastyczność umożliwia
określ miejsce docelowe aktywności, która powinna zostać uruchomiona za pomocą
intencji niejawnych, gdzie
nie będą miały sensu. Podobnie jak w przypadku miejsc docelowych fragmentów,
możesz skonfigurować etykietę, argumenty i precyzyjne linki.
activity(nav_routes.route_name) {
label = getString(R.string.activity_title)
// arguments, deepLinks...
activityClass = ActivityDestination::class
}
Miejsce docelowe wykresu nawigacyjnego
navigation()
Za pomocą funkcji DSL można utworzyć
zagnieżdżony wykres nawigacyjny.
Ta funkcja przyjmuje 3 argumenty: trasę do
przypisz do wykresu, trasę początkowego miejsca docelowego wykresu oraz
lambda w celu dalszego skonfigurowania wykresu. Prawidłowe elementy to m.in. inne miejsca docelowe,
precyzyjne linki,
etykietę opisową miejsca docelowego.
Ta etykieta może być przydatna do powiązania grafu nawigacyjnego z interfejsem użytkownika
komponenty korzystające z
Nawigacja
navigation("route_to_this_graph", nav_routes.home) {
// label, other destinations, deep links
}
Obsługa niestandardowych miejsc docelowych
Jeśli używasz tagu
nowy typ miejsca docelowego, który nie
obsługuje bezpośrednio konsolę DSL Kotlin, możesz dodać te miejsca docelowe do
DSL z 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
Każde miejsce docelowe może definiować argumenty opcjonalne lub wymagane. Działania
można zdefiniować za pomocą
argument()
funkcja w funkcji NavDestinationBuilder
, która jest klasą podstawową dla wszystkich
typów kreatora miejsc docelowych. Ta funkcja przyjmuje nazwę argumentu jako ciąg znaków
oraz funkcję lambda, która służy do tworzenia i konfigurowania
NavArgument
W obiekcie lambda możesz określić typ danych argumentu. Wartość domyślną, jeśli ma zastosowanie i wskazuje, czy dopuszcza on wartość null.
fragment<PlantDetailFragment>("${nav_routes.plant_detail}/{${nav_arguments.plant_id}}") {
label = getString(R.string.plant_details_title)
argument(nav_arguments.plant_id) {
type = NavType.StringType
defaultValue = getString(R.string.default_plant_id)
nullable = true // default false
}
}
Jeśli podano defaultValue
, można wywnioskować typ. Jeśli zarówno defaultValue
,
i type
, typy muszą być zgodne. Zobacz
Dokumentacja NavType
pełna lista dostępnych typów argumentów.
Podawanie typów niestandardowych
Niektóre typy danych, na przykład
ParcelableType
oraz
SerializableType
,
nie obsługują analizowania wartości z ciągów znaków używanych przez trasy lub precyzyjne linki.
Nie wymagają one odbicia w czasie działania. Poprzez dodanie pola niestandardowego
NavType
, możesz dokładnie określić, w jaki sposób Twój typ jest analizowany z trasy lub
precyzyjny link. Dzięki temu możesz używać
Serializacja Kotlin lub inna
bibliotek do kodowania i dekodowania niestandardowego typu bez odbicia lustrzanego.
Na przykład klasa danych, która reprezentuje parametry wyszukiwania przekazywane do
na ekranie wyszukiwania można zaimplementować zarówno Serializable
(aby zapewnić
obsługa kodowania/dekodowania) oraz Parcelize
(aby obsługiwać zapisywanie i przywracanie danych
z: Bundle
):
@Serializable
@Parcelize
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 dowolnego innego:
fragment<SearchFragment>(nav_routes.plant_search) {
label = getString(R.string.plant_search_title)
argument(nav_arguments.search_parameters) {
type = SearchParametersType
defaultValue = SearchParameters("cactus", emptyList())
}
}
NavType
obejmuje zapis i odczyt każdego pola, które
oznacza, że musisz użyć NavType
również przy przejściu do
miejsce docelowe, aby zapewnić zgodność formatów:
val params = SearchParameters("rose", listOf("available"))
val searchArgument = SearchParametersType.serializeAsValue(params)
navController.navigate("${nav_routes.plant_search}/$searchArgument")
Parametr ten można uzyskać z argumentów w miejscu docelowym:
val params: SearchParameters? = arguments?.getParcelable(nav_arguments.search_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 te same procedury zdefiniowane w Tworzenie precyzyjnego linku do miejsca docelowego mają zastosowanie do procesu tworzenia precyzyjny link za pomocą funkcji Kotlin DSL
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ć element
ręcznie za pomocą filtrów intencji do aktywności.
Podany filtr intencji powinien pasować do wzorca podstawowego adresu URL, działania
typu MIME precyzyjnych linków aplikacji.
Dla każdego pojedynczego precyzyjnego linku możesz podać bardziej szczegółowe deeplink
miejsce docelowe za pomocą
deepLink()
.
Funkcja DSL. Ta funkcja akceptuje żądania NavDeepLink
zawierające String
reprezentujący wzorzec identyfikatora URI, znacznik String
reprezentujący działania intencji oraz tag
String
reprezentujący mimeType .
Na przykład:
deepLink {
uriPattern = "http://www.example.com/plants/"
action = "android.intent.action.MY_ACTION"
mimeType = "image/*"
}
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.
Bardziej skomplikowany scenariusz niejawnego precyzyjnego linku, który określa też ścieżkę parametry oparte na zapytaniach wyświetlają się poniżej:
val baseUri = "http://www.example.com/plants"
fragment<PlantDetailFragment>(nav_routes.plant_detail) {
label = getString(R.string.plant_details_title)
deepLink(navDeepLink {
uriPattern = "${baseUri}/{id}"
})
deepLink(navDeepLink {
uriPattern = "${baseUri}/{id}?name={plant_name}"
})
}
Za pomocą interpolacja ciągów znaków aby uprościć definicję.
Ograniczenia
Wtyczka Safe Args
niekompatybilny z DSL Kotlin, ponieważ wtyczka szuka plików zasobów XML w celu
wygenerować zajęcia Directions
i Arguments
.
Więcej informacji
Zapoznaj się z informacjami na temat bezpieczeństwa typu nawigacji. znajdziesz więcej informacji o zapewnianiu bezpieczeństwa typu dla DSL Kotlin i Kod nawigacji.