You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose自定义主题未在模拟器显示,求助排查

问题:Jetpack Compose自定义主题不生效,按钮显示青色而非紫色

已将自定义Jetpack Compose主题应用到Activity,但在模拟器运行时,按钮未显示主题指定的紫色样式,反而呈现青色。

按钮显示青色的效果截图

相关代码如下:

Color.kt

import androidx.compose.ui.graphics.Color

val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)

val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

Theme.kt

private val DarkColorScheme = darkColorScheme(
    primary = Purple80,
    secondary = PurpleGrey80,
    tertiary = Pink80
)

private val LightColorScheme = lightColorScheme(
    primary = Purple40,
    secondary = PurpleGrey40,
    tertiary = Pink40

    /* Other default colors to override
    background = Color(0xFFFFFBFE),
    surface = Color(0xFFFFFBFE),
    onPrimary = Color.White,
    onSecondary = Color.White,
    onTertiary = Color.White,
    onBackground = Color(0xFF1C1B1F),
    onSurface = Color(0xFF1C1B1F),
    */
)

@Composable
fun MorseComposeAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColorScheme
        else -> LightColorScheme
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            val window = (view.context as Activity).window
            window.statusBarColor = colorScheme.primary.toArgb()
            WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = Typography,
        content = content
    )
}

MainActivity.kt

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

        val toner = ToneGenerator(AudioManager.STREAM_ALARM, ToneGenerator.MAX_VOLUME)
        val dotTime = 200
        val dashTime = 3 * dotTime

        setContent {
            MorseComposeAppTheme {
                Scaffold(
                    topBar = { TopAppBar(title = { Text("Morse Code") }) }
                ) {
                    Column(modifier = Modifier.fillMaxHeight()) {

                        Box(
                            modifier = Modifier
                                .weight(2f)
                                .padding(all = 2.dp)
                        ) {
                            SoundButton(label = "Dot") {
                                toner.startTone(ToneGenerator.TONE_SUP_DIAL, dotTime)
                            }
                        }


                        Box(
                            modifier = Modifier
                                .weight(1f)
                                .padding(all = 2.dp)
                        ) {
                            SoundButton(label = "Dash") {
                                toner.startTone(ToneGenerator.TONE_SUP_DIAL, dashTime)

                            }
                        }
                    }
                }
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun SoundButtonPreview() {
    MorseComposeAppTheme {
        SoundButton("Text") {}
    }
}

@Composable
fun SoundButton(label: String, onClick: () -> Unit) {
    Button(
        modifier = Modifier.fillMaxSize(),
        onClick = onClick,
    ) {
        Text(
            text = label,
        )
    }
}

问题原因

这不是模拟器问题,而是主题逻辑的优先级问题:
你的MorseComposeAppTheme中dynamicColor默认值为true,且当设备系统版本为Android 12(API 31)及以上时,会优先使用系统的动态颜色方案(dynamicLightColorScheme/dynamicDarkColorScheme),这套方案会根据系统主题色生成颜色,覆盖了你自定义的LightColorScheme和DarkColorScheme,所以按钮显示的是系统动态颜色中的青色,而非你定义的紫色。

解决方法

有两种常见解决方案:

方案1:关闭动态颜色

直接将MorseComposeAppTheme的dynamicColor默认参数改为false,强制使用自定义颜色方案:

@Composable
fun MorseComposeAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // 关闭动态颜色,默认使用自定义方案
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    // 剩余逻辑保持不变
}

方案2:在动态颜色基础上覆盖自定义颜色

如果你想保留动态颜色的适配性,同时替换特定颜色(比如primary),可以在生成动态颜色时覆盖对应值:

val colorScheme = when {
    dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
        val context = LocalContext.current
        if (darkTheme) {
            dynamicDarkColorScheme(context).copy(
                primary = Purple80,
                secondary = PurpleGrey80,
                tertiary = Pink80
            )
        } else {
            dynamicLightColorScheme(context).copy(
                primary = Purple40,
                secondary = PurpleGrey40,
                tertiary = Pink40
            )
        }
    }
    darkTheme -> DarkColorScheme
    else -> LightColorScheme
}

内容的提问来源于stack exchange,提问作者Amanda_C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 21:15:02