Bottom Navigation

Bottom Navigation

温馨提示:本文最后更新于2025-12-10 17:21:00,某些文章具有时效性,若有错误或已失效,请在下方留言

创建 Screen

HomeScreen 的可组合函数

@Composable
fun HomeScreen() {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(
            onClick = {}
        ) {
            Text(text = "Profile")
        }
        Button(
            onClick = {}
        ) {
            Text(text = "Settings")
        }
    }
}

ProfileScreen 的可组合函数

@Composable
fun ProfileScreen() {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Profile ID")

        Button(onClick = {}) {
            Text(text = "Go to Settings")
        }
    }
}

SettingsScreen 的可组合函数

@Composable
fun SettingsScreen() {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Settings Screen", fontSize = 40.sp)
        Button(onClick = {}) {
            Text(text = "Navigation to Home")
        }
    }
}

创建 Navigation Builder

创建枚举 NavRoute,代码如下

/**
 * 在 Kotlin 中,sealed 表示密封类,用于限制继承范围,让子类必须定义在同一个文件中。
 * 用途
 * 	•	实现 类型安全的枚举扩展
 * 	•	用于 UI State / Result 等有限集合类型
 */
sealed class NavRoute(val path: String) {
    /**
     *  object 创建一个全局唯一的对象(单例对象)。
     * */
    object Home: NavRoute("home")
    object Profile: NavRoute("profile") {
        val id = "id"
        val showDetails = "showDetails"
    }
    object Settings: NavRoute("settings")
}

创建 NavRoute

@Composable
fun HomeScreen(
    navigateToProfile: (Int, Boolean) -> Unit,
    navigateToSettings: () -> Unit
) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(
            onClick = {
                navigateToProfile(77, true)
            }
        ) {
            Text(text = "Profile")
        }
        Button(
            onClick = {
                navigateToSettings()
            }
        ) {
            Text(text = "Settings")
        }
    }
}
@Composable
fun ProfileScreen(
    id: Int,
    showDetails: Boolean,
    navigateToSettings: () -> Unit
) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Profile ID")

        Button(onClick = {
            navigateToSettings()
        }) {
            Text(text = "Go to Settings")
        }
    }
}
@Composable
fun SettingsScreen(
    navigateToHome: () -> Unit
) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Settings Screen", fontSize = 40.sp)
        Button(onClick = {
            navigateToHome()
        }) {
            Text(text = "Navigation to Home")
        }
    }
}

Nav Graph Builder

@Composable
fun NavGraph(navController: NavHostController) {
    //  使用navController 导航到定义在NavGraph中的不同可组合函数
}

fun addHomeScreen(
    navController: NavHostController,
    navGraphBuilder: NavGraphBuilder
) {
    // navGraphBuilder 为HomeScreen定义可组合路由

    // 定义导航目的地
    navGraphBuilder.composable(
        route = NavRoute.Home.path
    ) {
        HomeScreen(
            navigateToProfile = { id, showDetails ->
                navController.navigate(
                    NavRoute.Profile.path.plus(id.toString()).plus(showDetails.toString())
                )
            },
            navigateToSettings = {
                navController.navigate(
                    NavRoute.Settings.path
                )
            }
        )
    }
}

创建 NavController

// MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            NavigationAppTheme {
                // 创建导航控制器
                // 在Compose之间导航
                val navController = rememberNavController()

                NavGraph(navController = navController)
            }
        }
    }
}
@Composable
fun NavGraph(navController: NavHostController) {
    //  使用navController 导航到定义在NavGraph中的不同可组合函数
    //  NavHost 作为 NavGraph 的容器
    NavHost(
        navController = navController,
        startDestination = NavRoute.Home.path
    ) {
        addHomeScreen(
            navController,
            this
        )
        addProfileScreen(
            navController,
            this
        )
        addSettingsScreen(
            navController,
            this
        )
    }
}

fun addHomeScreen(
    navController: NavHostController,
    navGraphBuilder: NavGraphBuilder
) {
    // navGraphBuilder 为HomeScreen定义可组合路由

    // 定义导航目的地
    navGraphBuilder.composable(
        route = NavRoute.Home.path
    ) {
        HomeScreen(
            navigateToProfile = { id, showDetails ->
                navController.navigate(
                    NavRoute.Profile.path.plus(id.toString()).plus(showDetails.toString())
                )
            },
            navigateToSettings = {
                navController.navigate(
                    NavRoute.Settings.path
                )
            }
        )
    }
}

fun addProfileScreen(
    navController: NavController,
    navGraphBuilder: NavGraphBuilder
) {
    navGraphBuilder.composable(
        route = NavRoute.Profile.path.plus("/id/showDetails")
    ) {
        val  args = it.arguments
        ProfileScreen(
            id = args?.getInt(NavRoute.Profile.id)!!,
            showDetails= args.getBoolean(NavRoute.Profile.showDetails),
            navigateToSettings = {
                navController.navigate(
                    NavRoute.Settings.path
                )
            }
        )
    }
}

fun addSettingsScreen(
    navController: NavController,
    navGraphBuilder: NavGraphBuilder
) {
    navGraphBuilder.composable(
        route = NavRoute.Settings.path
    ) {
        SettingsScreen {
            navController.navigate(
                NavRoute.Home.path
            )
        }
    }
}

Screen 间数据传递

fun addHomeScreen(
    navController: NavHostController,
    navGraphBuilder: NavGraphBuilder
) {
    // navGraphBuilder 为HomeScreen定义可组合路由

    // 定义导航目的地
    navGraphBuilder.composable(
        route = NavRoute.Home.path
    ) {
        HomeScreen(
            navigateToProfile = { id, showDetails ->
                navController.navigate(
                    NavRoute.Profile.path.plus("/$id/$showDetails")
                )
            },
            navigateToSettings = {
                navController.navigate(
                    NavRoute.Settings.path
                )
            }
        )
    }
}

fun addProfileScreen(
    navController: NavController,
    navGraphBuilder: NavGraphBuilder
) {
    navGraphBuilder.composable(
        route = NavRoute.Profile.path.plus("/{id}/{showDetails}"),
        arguments = listOf(
            navArgument(NavRoute.Profile.id) {
                type = NavType.IntType
            },
            navArgument(NavRoute.Profile.showDetails) {
                type = NavType.BoolType
            }
        )
    ) {
        val  args = it.arguments
        ProfileScreen(
            id = args?.getInt(NavRoute.Profile.id)!!,
            showDetails= args.getBoolean(NavRoute.Profile.showDetails),
            navigateToSettings = {
                navController.navigate(
                    NavRoute.Settings.path
                )
            }
        )
    }
}

演示效果(便于查看,添加了额外的文本),如下所示

演示效果
演示效果

Nav Bottom 底部导航

open class Item(
    val path: String,
    val title: String,
    val image: ImageVector
)
sealed class NavItem {
    object Home: Item(
        NavRoute.Home.path.toString(),
        "Home",
        Icons.Default.Home
    )

    object Profile: Item(
        NavRoute.Profile.path.toString(),
        "Profile",
        Icons.Default.AccountCircle
    )

    object Settings: Item(
        NavRoute.Settings.path.toString(),
        "Settings",
        Icons.Default.Settings
    )
}
@Composable
fun BottomNavigationBar(navController: NavController) {
    // 1. 底部导航项目
    val navItems = listOf(NavItem.Home, NavItem.Profile, NavItem.Settings)

    // 2. 创建一个在重组中可以持久化状态的变量
    // rememberSaveable 是 Jetpack Compose 中用于 在重组(recomposition)和配置变化(如旋转屏幕)后保持状态 的状态保存函数。
    var selectedItem by rememberSaveable {
        mutableStateOf(0)
    }

    // 3. Navigation Bar
    NavigationBar {
        navItems.forEachIndexed { index, item ->
            NavigationBarItem(
                selected = selectedItem == index,
                onClick = {
                    selectedItem = index
                    navController.navigate(item.path) {
                        navController.graph.startDestinationRoute?.let {
                            route -> popUpTo(route) {
                                saveState = true
                        }
                            launchSingleTop = true
                            restoreState = true
                        }

                    }

                },
                icon = {
                    Icon(
                        imageVector = item.image,
                        contentDescription = item.title
                    )
                },
                label = {
                    Text(item.title)
                }
            )
        }
    }
}
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            NavigationAppTheme {
                // 创建导航控制器
                // 在Compose之间导航
                val navController = rememberNavController()
                Scaffold(bottomBar = {BottomNavigationBar(navController=navController)}) {
                    NavGraph(navController = navController)
                }
            }
        }
    }
}

运行效果,如下所示

运行效果
运行效果

Nav Bar 参数传递

@Composable
fun BottomNavigationBar(navController: NavController) {
    // 1. 底部导航项目
    val navItems = listOf(NavItem.Home, NavItem.Profile, NavItem.Settings)

    // 2. 创建一个在重组中可以持久化状态的变量
    // rememberSaveable 是 Jetpack Compose 中用于 在重组(recomposition)和配置变化(如旋转屏幕)后保持状态 的状态保存函数。
    var selectedItem by rememberSaveable {
        mutableStateOf(0)
    }

    // 3. Navigation Bar
    NavigationBar {
        navItems.forEachIndexed { index, item ->
            NavigationBarItem(
                selected = selectedItem == index,
                onClick = {
                    selectedItem = index

                    // 处理 Profile 的参数传递
                    val route = if (item.path == NavRoute.Profile.path) {
                        NavRoute.Profile.path.plus("/77/true")
                    } else {
                        item.path
                    }

                    navController.navigate(route) {
                        navController.graph.startDestinationRoute?.let {
                            route -> popUpTo(route) {
                                saveState = true
                        }
                            launchSingleTop = true
                            restoreState = true
                        }

                    }

                },
                icon = {
                    Icon(
                        imageVector = item.image,
                        contentDescription = item.title
                    )
                },
                label = {
                    Text(item.title)
                }
            )
        }
    }
}
运行效果
运行效果

NavBar 与 Screen 同步

@Composable
fun BottomNavigationBar(navController: NavController) {
    // 1. 底部导航项目
    val navItems = listOf(NavItem.Home, NavItem.Profile, NavItem.Settings)

    // NavBar 与 Screen 之间的同步
    // 2. 观察当前的 BackState 实体
    val navBackStackEntry by navController.currentBackStackEntryAsState()

    // 3, 获取当前的路由
    val currentRoute = navBackStackEntry?.destination?.route

    var selectedItem = navItems.indexOfFirst {
        it.path == currentRoute
    }

    // 4. 创建一个在重组中可以持久化状态的变量
    var selectedNavItem by rememberSaveable {
        mutableStateOf(if (selectedItem >= 0) selectedItem else 0)
    }



    // 5. Navigation Bar
    NavigationBar {
        navItems.forEachIndexed { index, item ->
            NavigationBarItem(
                selected = selectedItem == index,
                onClick = {
                    selectedNavItem = index

                    // 处理 Profile 的参数传毒
                    val route = if (item.path == NavRoute.Profile.path) {
                        NavRoute.Profile.path.plus("/77/true")
                    } else {
                        item.path
                    }

                    navController.navigate(route) {
                        navController.graph.startDestinationRoute?.let {
                            route -> popUpTo(route) {
                                saveState = true
                        }
                            launchSingleTop = true
                            restoreState = true
                        }

                    }

                },
                icon = {
                    Icon(
                        imageVector = item.image,
                        contentDescription = item.title
                    )
                },
                label = {
                    Text(item.title)
                }
            )
        }
    }
}

运行效果,如下所示

运行效果
运行效果
下载图标
NavigationApp.zip
zip文件
© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容