如何在Android Jetpack Compose中实现带圆角效果的底部导航栏
实现方案
核心思路
Jetpack Compose的NavigationBar(Material3组件)本身支持自定义形状属性,只需要给它配置圆角形状,再调整布局边距就能实现你要的效果。
具体实现步骤
- 首先确保你项目中已经引入了Compose Material3依赖:
implementation "androidx.compose.material3:material3:1.2.1"
- 然后在布局中自定义
NavigationBar的shape属性,同时可以根据需求加边距实现悬浮效果,完整参考代码如下:
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Message import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.outlined.Home import androidx.compose.material.icons.outlined.Message import androidx.compose.material.icons.outlined.Person import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController @Composable fun RoundedBottomNavigationDemo() { val navController = rememberNavController() // 底部导航路由列表,按需替换为你自己的页面配置 val navItems = listOf( NavItem.Home, NavItem.Message, NavItem.Profile ) Scaffold( bottomBar = { NavigationBar( // 核心配置:设置圆角,仅要顶部圆角就只配置topStart和topEnd,要悬浮款就传统一圆角值 shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp), modifier = Modifier // 悬浮款额外加左右和底部边距即可 .padding(horizontal = 12.dp, bottom = 18.dp) // 自定义阴影时圆角要和上方shape保持一致 .shadow(elevation = 8.dp, shape = RoundedCornerShape(24.dp)), containerColor = Color.White, contentColor = MaterialTheme.colorScheme.primary ) { val currentBackStackEntry by navController.currentBackStackEntryAsState() val currentDestination = currentBackStackEntry?.destination navItems.forEach { item -> val isSelected = currentDestination?.hierarchy?.any { it.route == item.route } == true NavigationBarItem( selected = isSelected, onClick = { navController.navigate(item.route) { popUpTo(navController.graph.findStartDestination().id) launchSingleTop = true } }, icon = { Icon( imageVector = if (isSelected) item.selectedIcon else item.unselectedIcon, contentDescription = item.label ) }, label = { Text(item.label) } ) } } } ) { innerPadding -> // 页面内容区域,记得应用innerPadding避免内容和导航栏重叠 NavHost( navController = navController, startDestination = NavItem.Home.route, modifier = Modifier.padding(innerPadding) ) { // 注册你的页面路由,替换为实际页面组件 composable(NavItem.Home.route) { /* 首页组件 */ } composable(NavItem.Message.route) { /* 消息页组件 */ } composable(NavItem.Profile.route) { /* 个人页组件 */ } } } } // 示例导航项实体类,按需修改 sealed class NavItem( val route: String, val label: String, val selectedIcon: ImageVector, val unselectedIcon: ImageVector ) { object Home : NavItem( route = "home", label = "首页", selectedIcon = Icons.Filled.Home, unselectedIcon = Icons.Outlined.Home ) object Message : NavItem( route = "message", label = "消息", selectedIcon = Icons.Filled.Message, unselectedIcon = Icons.Outlined.Message ) object Profile : NavItem( route = "profile", label = "我的", selectedIcon = Icons.Filled.Person, unselectedIcon = Icons.Outlined.Person ) }
注意事项
- 如果出现导航栏和系统底部手势导航条重叠的问题,可以给
NavigationBar的modifier追加navigationBarsPadding(),自动适配系统底部边距。 - 圆角数值、阴影大小、边距数值都可以根据你的设计稿需求灵活调整。
内容的提问来源于stack exchange,提问作者Oğuzhan Aslan
相关产品推荐
相关产品推荐

