如果在 android jetpack compose 中选择和取消选择,如何更改图标,就像我们在 xml 中用于选择状态的选择器一样?

How to change icon if selected and unselected in android jetpack compose for NavigationBar like selector we use in xml for selected state?

我想在 NavigationBar 中使用基于选定状态的轮廓和填充图标,就像 google 地图应用程序一样,使用 Jetpack Compose。在 xml 的情况下,我们使用选择器,那么我们用什么来撰写?

这是我的代码 ->

MainActivity.kt

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

        // Handle the splash screen transition.
        installSplashScreen()
        setContent {
            MyApp()
        }
    }
}

@ExperimentalMaterial3Api
@Composable
fun MyApp() {
    MyTheme {
        val items = listOf(
            Screen.HomeScreen,
            Screen.MusicScreen,
            Screen.ProfileScreen
        )
        val navController = rememberNavController()
        Scaffold(
            bottomBar = {
                NavigationBar {
                    val navBackStackEntry by navController.currentBackStackEntryAsState()
                    val currentDestination = navBackStackEntry?.destination
                    items.forEach { screen ->
                        NavigationBarItem(
                            icon = {
                                Icon(
                                    screen.icon_outlined,
                                    contentDescription = screen.label.toString()
                                )
                            },
                            label = { Text(stringResource(screen.label)) },
                            selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                            onClick = {
                                navController.navigate(screen.route) {
                                    // Pop up to the start destination of the graph to
                                    // avoid building up a large stack of destinations
                                    // on the back stack as users select items
                                    popUpTo(navController.graph.findStartDestination().id) {
                                        saveState = true
                                    }
                                    // Avoid multiple copies of the same destination when
                                    // reselecting the same item
                                    launchSingleTop = true
                                    // Restore state when reselecting a previously selected item
                                    restoreState = true
                                }
                            }
                        )
                    }
                }
            }
        ) { innerPadding ->
            NavHost(
                navController,
                startDestination = Screen.HomeScreen.route,
                Modifier.padding(innerPadding)
            ) {
                composable(route = Screen.HomeScreen.route) {
                    HomeScreen()
                }
                composable(route = Screen.MusicScreen.route) {
                    MusicScreen()
                }
                composable(route = Screen.ProfileScreen.route) {
                    ProfileScreen()
                }
            }
        }
    }
}

@ExperimentalMaterial3Api
@Preview(
    showBackground = true, name = "Light mode",
    uiMode = Configuration.UI_MODE_NIGHT_NO or Configuration.UI_MODE_TYPE_NORMAL
)
@Preview(
    showBackground = true, name = "Night mode",
    uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL
)
@Composable
fun DefaultPreview() {
    MyApp()
}

Screen.kt

sealed class Screen(
    val route: String,
    @StringRes val label: Int,
    val icon_outlined: ImageVector,
    val icon_filled: ImageVector
) {
    object HomeScreen : Screen(
        route = "home_screen",
        label = R.string.home,
        icon_outlined = Icons.Outlined.Home,
        icon_filled = Icons.Filled.Home
    )

    object MusicScreen : Screen(
        route = "music_screen",
        label = R.string.music,
        icon_outlined = Icons.Outlined.LibraryMusic,
        icon_filled = Icons.Filled.LibraryMusic,
    )

    object ProfileScreen : Screen(
        route = "profile_screen",
        label = R.string.profile,
        icon_outlined = Icons.Outlined.AccountCircle,
        icon_filled = Icons.Filled.AccountCircle,
    )
}

主页Screen.kt

@Composable
fun HomeScreen() {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Surface(color = MaterialTheme.colorScheme.background) {
            Text(
                text = "Home",
                color = Color.Red,
                fontSize = MaterialTheme.typography.displayLarge.fontSize,
                fontWeight = FontWeight.Bold
            )
        }
    }
}

@Preview(
    showBackground = true, name = "Light mode",
    uiMode = Configuration.UI_MODE_NIGHT_NO or Configuration.UI_MODE_TYPE_NORMAL
)
@Preview(
    showBackground = true, name = "Night mode",
    uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL
)
@Composable
fun HomeScreenPreview() {
    HomeScreen()
}

我还需要使用选择器 xml 还是在 Jetpack Compose 中有替代方法?

是的,你只需要根据selected状态做一个简单的if语句,像这样:

items.forEach { screen ->
    val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true
    NavigationBarItem(
        icon = {
            Icon(
                if (selected) screen.icon_filled else screen.icon_outlined,
                contentDescription = screen.label.toString()
            )
        },
        selected = selected,
    )
}