Eine meiner bevorzugten Methoden zur Navigation zwischen verschiedenen Views in einer mobilen App ist die Tab-Navigation. Ich bevorzuge sie, weil ich sie mit meinem Daumen mit einer Hand bedienen kann.
Folglich ist die Integration von Tab-Navigation zu einer Standardpraxis in meiner mobilen App-Entwicklung geworden. Gluecklicherweise gibt es eine Kotlin Multiplatform Mobile Bibliothek, die es uns ermoeglicht, Navigationscode einmal zu schreiben und plattformuebergreifend wiederzuverwenden.
Dieser Beitrag beschreibt die Schritte zum Hinzufuegen von drei Beispiel-Tabs zu einer Anwendung. Wie bei meinem vorherigen Beitrag zu Kotlin Multiplatform wende ich dieses Muster typischerweise in einer neuen App an, indem ich die relevanten Code-Snippets kopiere und einfuege.
Unten ist eine Darstellung des Beispiel-App-Layouts: Eine Titelleiste oben, der Hauptinhalt in der Mitte und eine Navigationsleiste unten.

Wir beginnen mit dem Hinzufuegen der Abhaengigkeiten in gradle/libs.versions.toml:
[versions]
...
voyager = "1.0.0"
[libraries]
...
voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" }
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }Als Naechstes fuegen wir die Abhaengigkeiten zu unserem Source Set hinzu, das sich in composeApp/build.gradle.kts befindet.
kotlin {
...
sourceSets {
...
commonMain.dependencies {
...
implementation(libs.voyager.tab.navigator)
implementation(libs.voyager.transitions)
}
}
}Synchronisiere nun deine IDE, damit die Aenderungen wirksam werden.
Als Naechstes fuege Wrapper-Code fuer die Navigationselemente hinzu. Platziere diesen Code in der Datei composeApp/src/commonMain/kotlin/TabNavigationItem.kt.
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.runtime.Composable
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
import cafe.adriel.voyager.navigator.tab.Tab
@Composable
fun RowScope.TabNavigationItem(tab: Tab) {
val tabNavigator = LocalTabNavigator.current
BottomNavigationItem(
selected = tabNavigator.current.key == tab.key,
onClick = { tabNavigator.current = tab },
icon = { Icon(painter = tab.options.icon!!, contentDescription = tab.options.title) }
)
}Lass uns drei Tabs in unserer Beispielanwendung erstellen: “Home”, “Favourites” und “Profile”.
Die Datei fuer den “Home”-Tab befindet sich unter composeApp/src/commonMain/kotlin/HomeTab.kt.
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
object HomeTab: Tab {
override val options: TabOptions
@Composable
get() {
val icon = rememberVectorPainter(Icons.Default.Home)
return remember {
TabOptions(
index = 0u,
title = "Home",
icon = icon
)
}
}
@Composable
override fun Content() {
Text("Home")
}
}Als Naechstes fuege den “Favorites”-Tab in composeApp/src/commonMain/kotlin/FavoritesTab.kt hinzu.
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
object FavoritesTab: Tab {
override val options: TabOptions
@Composable
get() {
val icon = rememberVectorPainter(Icons.Default.Favorite)
return remember {
TabOptions(
index = 1u,
title = "Favorites",
icon = icon
)
}
}
@Composable
override fun Content() {
Text("Favorites")
}
}Schliesslich findest du den ‘Profile’-Tab in composeApp/src/commonMain/kotlin/ProfileTab.kt.
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
object ProfileTab: Tab {
override val options: TabOptions
@Composable
get() {
val icon = rememberVectorPainter(Icons.Default.Person)
return remember {
TabOptions(
index = 2u,
title = "Profile",
icon = icon
)
}
}
@Composable
override fun Content() {
Text("Profile")
}
}Wir fuegen alles in der Datei composeApp/src/commonMain/kotlin/App.kt zusammen, wo wir auch ein Scaffold erstellen.
Um mehr darueber zu erfahren, was ein Scaffold ist, klicke auf den Link unten.
Jetpack Compose - What’s a Scaffold
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.BottomNavigation
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import cafe.adriel.voyager.navigator.tab.CurrentTab
import cafe.adriel.voyager.navigator.tab.TabDisposable
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
import cafe.adriel.voyager.navigator.tab.TabNavigator
@OptIn(ExperimentalResourceApi::class)
@Composable
fun App() {
MaterialTheme {
TabNavigator(
HomeTab,
tabDisposable = {
TabDisposable(
navigator = it,
tabs = listOf(HomeTab, FavoritesTab, ProfileTab)
)
}
) { tabNavigator ->
Scaffold(
topBar = {
TopAppBar(
title = { Text(text = tabNavigator.current.options.title) }
)
},
content = {
CurrentTab()
},
bottomBar = {
BottomNavigation {
TabNavigationItem(HomeTab)
TabNavigationItem(FavoritesTab)
TabNavigationItem(ProfileTab)
}
}
)
}
}
}Das war’s - wir haben erfolgreich Tab-Navigation zu unserer Beispielanwendung hinzugefuegt.
Ich hoffe, du fandest diesen Artikel nuetzlich.