如何在 Compose 中排列 BottomNavigationItems?

发布于 2025-01-19 03:48:12 字数 1083 浏览 0 评论 0原文

输入图片这里的描述

我怎样才能安排两个内部BottomNav项目,使它们不那么靠近“+”FAB? 我尝试围绕 forEach 显示带有行的项目并使用排列修改器,如下所示:

Row(horizontalArrangement = Arrangement.SpaceBetween) { //Not working :(
items.forEach { item ->
    BottomNavigationItem(
        icon = { Icon(painterResource(id = item.icon), contentDescription = item.title) },
        label = { Text(text = item.title) },
        selectedContentColor = Color.White,
        unselectedContentColor = Color.White.copy(0.4f),
        alwaysShowLabel = true,
        selected = currentRoute == item.route,
        onClick = {
            navController.navigate(item.route) { 
                navController.graph.startDestinationRoute?.let { route ->
                    popUpTo(route) {
                        saveState = true
                    }
                } 
                launchSingleTop = true 
                restoreState = true
            }
        }
    )
}

}

不幸的是,这不起作用

enter image description here

How can I arrange the two inner BottomNav Items so that they are not so close to the "+" FAB?
I tried surrounding the forEach which displays the Items with a Row and use the Arrangement modifier like so:

Row(horizontalArrangement = Arrangement.SpaceBetween) { //Not working :(
items.forEach { item ->
    BottomNavigationItem(
        icon = { Icon(painterResource(id = item.icon), contentDescription = item.title) },
        label = { Text(text = item.title) },
        selectedContentColor = Color.White,
        unselectedContentColor = Color.White.copy(0.4f),
        alwaysShowLabel = true,
        selected = currentRoute == item.route,
        onClick = {
            navController.navigate(item.route) { 
                navController.graph.startDestinationRoute?.let { route ->
                    popUpTo(route) {
                        saveState = true
                    }
                } 
                launchSingleTop = true 
                restoreState = true
            }
        }
    )
}

}

Unfortunately thats not working

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

懷念過去 2025-01-26 03:48:12

Arrangement.SpaceBetween 按预期工作 - 它在项目之间添加了一个间隔:

放置子项时,使其在主轴上均匀分布,第一个子项之前或最后一个子项之后没有可用空间。视觉上:1##2##3

您需要让您的 Row 了解 FAB 位置。您可以在行中间添加带有 Modifier.weight 的间隔符,例如如下所示:

items.forEachIndexed { i, item ->
    if (i == items.count() / 2) {
        Spacer(Modifier.weight(1f))
    }
    BottomNavigationItem(
        // ...

Arrangement.SpaceBetween works as expected - it adds a spacer between items:

Place children such that they are spaced evenly across the main axis, without free space before the first child or after the last child. Visually: 1##2##3

You need to let your Row know about FAB location. You can add a spacer with Modifier.weight in the middle of your row, for example like this:

items.forEachIndexed { i, item ->
    if (i == items.count() / 2) {
        Spacer(Modifier.weight(1f))
    }
    BottomNavigationItem(
        // ...
缱绻入梦 2025-01-26 03:48:12

您可以使用 BottomAppBar &给它 cutoutShape 并在中间添加一个虚拟项目。它会给你你想要的结果。

输出:

bottomnav fab

代码示例:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AppTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    BottomBarWithFabDem()
                }
            }
        }
    }
}

val items = listOf(
    Screen.PickUp,
    Screen.Explore,
    Screen.Camera,
    Screen.Favorites,
    Screen.Profile
)

sealed class Screen(val route: String?, val title: String?, val icon: ImageVector?) {
    object PickUp : Screen("pickup", "PickUp", Icons.Default.ShoppingCart)
    object Explore : Screen("explore", "Explore", Icons.Default.Info)
    object Camera : Screen("camera", null, null)
    object Favorites : Screen("favorites", "Fav", Icons.Default.Favorite)
    object Profile : Screen("profile", "Profile", Icons.Default.Person)
}

@Composable
fun BottomBarWithFabDem() {
    val navController = rememberNavController()
    Scaffold(
        bottomBar = {
            BottomNav(navController)
        },
        floatingActionButtonPosition = FabPosition.Center,
        isFloatingActionButtonDocked = true,
        floatingActionButton = {
            FloatingActionButton(
                shape = CircleShape,
                onClick = {
                    Screen.Camera.route?.let {
                        navController.navigate(it) {
                            popUpTo(navController.graph.findStartDestination().id) {
                                saveState = true
                            }
                            launchSingleTop = true
                            restoreState = true
                        }
                    }
                    Screen.Camera.route?.let { navController.navigate(it) }
                },
                contentColor = Color.White
            ) {
                Icon(imageVector = Icons.Filled.Add, contentDescription = "Add icon")
            }
        }
    ) {
        MainScreenNavigation(navController)
    }
}

@Composable
fun MainScreenNavigation(navController: NavHostController) {
    NavHost(navController, startDestination = Screen.Profile.route!!) {
        composable(Screen.Profile.route) {}
        composable(Screen.Explore.route!!) {}
        composable(Screen.Favorites.route!!) {}
        composable(Screen.PickUp.route!!) {}
        composable(Screen.Camera.route!!) {}
    }
}

@Composable
fun BottomNav(navController: NavController) {
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination
    BottomAppBar(cutoutShape = CircleShape, modifier = Modifier.height(64.dp)) {
        Row {
            items.forEachIndexed { index, it ->
                if (index != 2) {
                    // Main item
                    BottomNavigationItem(
                        icon = {
                            it.icon?.let {
                                Icon(
                                    imageVector = it,
                                    contentDescription = "",
                                    modifier = Modifier.size(35.dp),
                                    tint = Color.White

                                )
                            }
                        },
                        label = {
                            it.title?.let {
                                Text(
                                    text = it,
                                    color = Color.White
                                )
                            }
                        },
                        selected = currentRoute?.hierarchy?.any { it.route == it.route } == true,
                        selectedContentColor = Color(R.color.purple_700),
                        unselectedContentColor = Color.White.copy(alpha = 0.4f),
                        onClick = {}
                    )
                } else {
                    // placeholder for center fab
                    BottomNavigationItem(
                        icon = {},
                        label = { },
                        selected = false,
                        onClick = { },
                        enabled = false
                    )
                }
            }
        }

    }
}

You can use BottomAppBar & give it cutoutShape with a dummy item in the middle. It would give you your desired results.

Output:

bottomnav fab

Code Sample:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AppTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    BottomBarWithFabDem()
                }
            }
        }
    }
}

val items = listOf(
    Screen.PickUp,
    Screen.Explore,
    Screen.Camera,
    Screen.Favorites,
    Screen.Profile
)

sealed class Screen(val route: String?, val title: String?, val icon: ImageVector?) {
    object PickUp : Screen("pickup", "PickUp", Icons.Default.ShoppingCart)
    object Explore : Screen("explore", "Explore", Icons.Default.Info)
    object Camera : Screen("camera", null, null)
    object Favorites : Screen("favorites", "Fav", Icons.Default.Favorite)
    object Profile : Screen("profile", "Profile", Icons.Default.Person)
}

@Composable
fun BottomBarWithFabDem() {
    val navController = rememberNavController()
    Scaffold(
        bottomBar = {
            BottomNav(navController)
        },
        floatingActionButtonPosition = FabPosition.Center,
        isFloatingActionButtonDocked = true,
        floatingActionButton = {
            FloatingActionButton(
                shape = CircleShape,
                onClick = {
                    Screen.Camera.route?.let {
                        navController.navigate(it) {
                            popUpTo(navController.graph.findStartDestination().id) {
                                saveState = true
                            }
                            launchSingleTop = true
                            restoreState = true
                        }
                    }
                    Screen.Camera.route?.let { navController.navigate(it) }
                },
                contentColor = Color.White
            ) {
                Icon(imageVector = Icons.Filled.Add, contentDescription = "Add icon")
            }
        }
    ) {
        MainScreenNavigation(navController)
    }
}

@Composable
fun MainScreenNavigation(navController: NavHostController) {
    NavHost(navController, startDestination = Screen.Profile.route!!) {
        composable(Screen.Profile.route) {}
        composable(Screen.Explore.route!!) {}
        composable(Screen.Favorites.route!!) {}
        composable(Screen.PickUp.route!!) {}
        composable(Screen.Camera.route!!) {}
    }
}

@Composable
fun BottomNav(navController: NavController) {
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination
    BottomAppBar(cutoutShape = CircleShape, modifier = Modifier.height(64.dp)) {
        Row {
            items.forEachIndexed { index, it ->
                if (index != 2) {
                    // Main item
                    BottomNavigationItem(
                        icon = {
                            it.icon?.let {
                                Icon(
                                    imageVector = it,
                                    contentDescription = "",
                                    modifier = Modifier.size(35.dp),
                                    tint = Color.White

                                )
                            }
                        },
                        label = {
                            it.title?.let {
                                Text(
                                    text = it,
                                    color = Color.White
                                )
                            }
                        },
                        selected = currentRoute?.hierarchy?.any { it.route == it.route } == true,
                        selectedContentColor = Color(R.color.purple_700),
                        unselectedContentColor = Color.White.copy(alpha = 0.4f),
                        onClick = {}
                    )
                } else {
                    // placeholder for center fab
                    BottomNavigationItem(
                        icon = {},
                        label = { },
                        selected = false,
                        onClick = { },
                        enabled = false
                    )
                }
            }
        }

    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文