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

Android Kotlin开发如何在夜间模式基础上实现AMOLED主题

Android Kotlin 实现AMOLED纯黑主题规范方案

基于你现有的主题切换框架,只需要做少量改造即可新增AMOLED主题选项,不需要重构原有逻辑。


1. 新增AMOLED主题资源

首先在主题资源文件中新增AMOLED专属样式,核心是将界面背景、系统栏设置为纯黑,控件层级用深灰区分即可:

<!-- res/values-night/themes.xml 内新增 -->
<style name="Theme.YourApp.Amoled" parent="Theme.Material3.DayNight.NoActionBar">
    <!-- 核心纯黑背景 -->
    <item name="android:windowBackground">@android:color/black</item>
    <item name="colorSurface">@android:color/black</item>
    <item name="colorOnSurface">@color/white</item>
    <!-- 适配edge-to-edge的系统栏纯黑设置 -->
    <item name="android:statusBarColor">@android:color/black</item>
    <item name="android:navigationBarColor">@android:color/black</item>
    <!-- 卡片、弹窗等层级控件建议用#121212这类深灰,和纯黑背景做出视觉区分 -->
    <item name="colorSurfaceVariant">@color/deep_gray</item>
</style>

在设置页的主题选择列表中,新增一个选项值nightModeAmoled即可。


2. 重构ThemeHelper逻辑

你原有代码的核心问题是主题应用时机不对、硬编码太多,改造后统一处理四种主题状态(跟随系统、亮色、普通暗色、AMOLED纯黑):

import android.graphics.Color
import android.util.TypedValue

object ThemeHelper {
    // 统一管理主题常量,避免硬编码拼写错误
    const val THEME_FOLLOW_SYSTEM = "nightModeFollowSystem"
    const val THEME_LIGHT = "nightModeOff"
    const val THEME_DARK = "nightModeOn"
    const val THEME_AMOLED = "nightModeAmoled"

    private fun isNightMode(context: Context): Boolean {
        return context.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
    }

    fun getSelectedTheme(context: Context): String {
        val prefs = PreferenceManager.getDefaultSharedPreferences(context)
        return prefs.getString("modTema", THEME_FOLLOW_SYSTEM) ?: THEME_FOLLOW_SYSTEM
    }

    /**
     * 必须在Activity的super.onCreate调用前执行
     */
    fun applyTheme(activity: Activity) {
        when(getSelectedTheme(activity)) {
            THEME_LIGHT -> {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
                activity.setTheme(R.style.Theme_YourApp)
            }
            THEME_DARK -> {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
                activity.setTheme(R.style.Theme_YourApp)
            }
            THEME_AMOLED -> {
                // AMOLED属于暗色模式分支,先开启夜间模式再加载纯黑主题
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
                activity.setTheme(R.style.Theme_YourApp_Amoled)
            }
            THEME_FOLLOW_SYSTEM -> {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
                activity.setTheme(R.style.Theme_YourApp)
            }
        }
    }

    fun recreateIfNeeded(activity: Activity) {
        val currentSelected = getSelectedTheme(activity)
        val currentIsNight = isNightMode(activity)
        var needRecreate = true

        // 匹配当前状态和选中主题,完全一致则不重建
        when {
            currentSelected == THEME_LIGHT && !currentIsNight -> needRecreate = false
            currentSelected == THEME_DARK && currentIsNight -> needRecreate = false
            currentSelected == THEME_AMOLED && currentIsNight && isCurrentAmoled(activity) -> needRecreate = false
            currentSelected == THEME_FOLLOW_SYSTEM -> {
                val systemIsNight = (activity.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
                needRecreate = currentIsNight != systemIsNight
            }
        }

        if (needRecreate) {
            val intent = activity.intent.apply {
                putExtra("TEMA_CAMBIATO", true)
            }
            activity.finish()
            activity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
            activity.startActivity(intent)
        }
    }

    // 校验当前是否已经加载AMOLED主题
    private fun isCurrentAmoled(activity: Activity): Boolean {
        val typedValue = TypedValue()
        activity.theme.resolveAttribute(android.R.attr.windowBackground, typedValue, true)
        return typedValue.data == Color.BLACK
    }
}

3. 修正MainActivity主题应用时机

你原来把setDefaultNightMode放在super.onCreate之后是不符合官方规范的,会触发重复重建,调整到super.onCreate之前调用即可:

override fun onCreate(savedInstanceState: Bundle?) {
    // 先应用主题,再执行其他初始化
    ThemeHelper.applyTheme(this)
    WindowCompat.setDecorFitsSystemWindows(window, false)
    super.onCreate(savedInstanceState)
    // 原有setContentView、导航初始化等逻辑保留
}

override fun onResume() {
    super.onResume()
    if (intent.extras?.getBoolean("TEMA_CAMBIATO") == true) {
        intent.putExtra("TEMA_CAMBIATO", false)
        navController.navigate(R.id.SettingsFragment)
    }
}

4. 调整设置页监听逻辑

把原有重建方法替换成新的判断方法即可:

override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
    if (isAdded && key == "modTema") {
        ThemeHelper.recreateIfNeeded(requireActivity())
    }
}

额外适配提示

  • 如果使用Material组件,确保主题parent继承自对应版本的Material主题,否则控件颜色不会自动适配
  • AMOLED主题下不要所有元素都用纯黑,卡片、弹窗、底部栏用深灰色做层级区分,避免界面没有层次
  • 如果适配了动态取色,记得在AMOLED主题中覆盖surface相关颜色为纯黑即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:48:52