Compose BottomNavigation主题启动不生效问题技术求助
我用DataStore实现了一个简易主题切换应用,应用启动时文本颜色、背景色等样式可正常更新,但BottomNavigation的背景色与内容色保持默认状态,仅手动切换主题时才会更新。最后一张场景中BottomNavigation背景应为蓝色,但实际显示为默认黑色。
相关代码
MainActivity
class MainActivity: ComponentActivity() { private lateinit var appDataStore: AppDataStore override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) appDataStore = AppDataStore(applicationContext) setContent { val themeFlow = appDataStore.theme.collectAsState(initial = CustomTheme.A) AppTheme(theme = themeFlow.value) { MainScreen(dataStore = appDataStore) } } } } @Composable fun MainScreen(dataStore: AppDataStore) { val navController = rememberNavController() Scaffold(bottomBar = { BottomNavigationBar(navController = navController) }) { paddingValues -> Box(modifier = Modifier.padding(bottom = paddingValues.calculateBottomPadding())) { Column(modifier = Modifier.fillMaxSize()) { NavigationGraph(navController = navController, dataStore = dataStore) } } } } @Composable fun NavigationGraph(navController: NavHostController, startDestination: String = "screenB", dataStore: AppDataStore) { NavHost(navController, startDestination = startDestination) { composable(BottomNavigationModel.A.navigationPath) { val screenDataModel = ScreenDataModel(textId = R.string.screen_A) ScreenA(screenDataModel) } composable(BottomNavigationModel.B.navigationPath) { val screenDataModel = ScreenDataModel(textId = R.string.screen_B) ScreenB(screenDataModel, dataStore) } composable(BottomNavigationModel.C.navigationPath) { val screenDataModel = ScreenDataModel(textId = R.string.screen_C) ScreenC(screenDataModel) } } }
Bottom Navigation Bar
@Composable fun BottomNavigationBar(navController: NavController) { val items = listOf(BottomNavigationModel.A, BottomNavigationModel.B, BottomNavigationModel.C) BottomNavigation(backgroundColor = MaterialTheme.customColors.bottomNavigationBackgroundColor, contentColor = MaterialTheme.customColors.bottomNavigationContentColor) { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route items.forEach { item -> BottomNavigationItem( icon = { Icon(painterResource(id = item.iconId), contentDescription = "") }, label = { Text(text = stringResource(id = item.titleId), fontSize = 10.sp) }, selectedContentColor = MaterialTheme.customColors.bottomNavigationContentColor, unselectedContentColor = MaterialTheme.customColors.bottomNavigationContentColor.copy(alpha = 0.4f), alwaysShowLabel = true, selected = currentRoute == item.navigationPath, onClick = { navController.navigate(item.navigationPath) { navController.graph.startDestinationRoute?.let { navigationPath -> popUpTo(navigationPath) { saveState = true } } launchSingleTop = true restoreState = true } } ) } } }
Theme
val LocalColors = staticCompositionLocalOf { ThemeACustomColors } val MaterialTheme.customColors: CustomColors @Composable @ReadOnlyComposable get() = LocalColors.current @Composable fun AppTheme( theme: CustomTheme = CustomTheme.A, content: @Composable () -> Unit ) { val colors = when (theme) { CustomTheme.B -> ThemeBCustomColors CustomTheme.C -> ThemeCCustomColors CustomTheme.D -> ThemeDCustomColors else -> ThemeACustomColors } CompositionLocalProvider(LocalColors provides colors) { MaterialTheme( colors = colors.material, typography = Typography, shapes = Shapes, content = content ) } val useDarkIcons = when (theme) { CustomTheme.C, CustomTheme.D -> false else -> true } val systemUiController = rememberSystemUiController() systemUiController.setStatusBarColor(colors.statusBarColor, useDarkIcons) }
Gradle (Project)
buildscript { ext { compose_ui_version = '1.2.0' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '7.4.2' apply false id 'com.android.library' version '7.4.2' apply false id 'org.jetbrains.kotlin.android' version '1.7.0' apply false }
Gradle (Module)
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' } android { namespace 'com.example.themeapp' compileSdk 33 defaultConfig { applicationId "com.example.themeapp" minSdk 21 targetSdk 33 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion '1.2.0' } packagingOptions { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' } } } dependencies { implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation 'androidx.activity:activity-compose:1.3.1' implementation "androidx.compose.ui:ui:$compose_ui_version" implementation "androidx.navigation:navigation-compose:2.5.3" implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version" implementation 'androidx.compose.material:material:1.2.0' implementation "com.google.accompanist:accompanist-systemuicontroller:0.27.0" implementation("androidx.datastore:datastore-preferences:1.0.0") testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version" }
场景说明
- Theme A - 默认主题
- Theme B - 已保存主题
- 底部导航栏背景应为蓝色(实际显示默认黑色)
问题原因
启动时主题状态从DataStore加载完成后触发AppTheme重组,但BottomNavigationBar仅依赖navController的栈状态变化,未响应主题状态更新,导致样式未同步。
解决方案
在BottomNavigationBar中添加主题颜色作为重组触发键,确保主题变化时强制重组:
@Composable fun BottomNavigationBar(navController: NavController) { val items = listOf(BottomNavigationModel.A, BottomNavigationModel.B, BottomNavigationModel.C) // 添加key,当自定义颜色变化时强制重组 key(MaterialTheme.customColors) { BottomNavigation( backgroundColor = MaterialTheme.customColors.bottomNavigationBackgroundColor, contentColor = MaterialTheme.customColors.bottomNavigationContentColor ) { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route items.forEach { item -> BottomNavigationItem( icon = { Icon(painterResource(id = item.iconId), contentDescription = "") }, label = { Text(text = stringResource(id = item.titleId), fontSize = 10.sp) }, selectedContentColor = MaterialTheme.customColors.bottomNavigationContentColor, unselectedContentColor = MaterialTheme.customColors.bottomNavigationContentColor.copy(alpha = 0.4f), alwaysShowLabel = true, selected = currentRoute == item.navigationPath, onClick = { navController.navigate(item.navigationPath) { navController.graph.startDestinationRoute?.let { navigationPath -> popUpTo(navigationPath) { saveState = true } } launchSingleTop = true restoreState = true } } ) } } } }
同时可检查CustomTheme对应的颜色配置,确保ThemeBCustomColors中的bottomNavigationBackgroundColor确实设置为预期的蓝色,避免颜色定义错误导致的问题。
内容的提问来源于stack exchange,提问作者apphitect
相关产品推荐
相关产品推荐

