Android 深色模式适配 管理APP内主题切换工具 可定时开启

Android 深色模式适配 管理APP内主题切换工具 可定时开启

  • 前言
  • 深色模式适配
  • APP主题切换工具
  • 使用方法
    • 设置主题
    • 设置定时
    • 应用设置
  • 完事

前言

今天将深色模式的管理整合到一个文件当中,想着自己深色模式适配的文章上,结果才发现我原来没有写这篇文章。。。为啥我脑子里记得我好像写过的呢,啊,怕是在脑海里曾经构思过,然后脑子骗自己以为写了。

闲话少说开码

深色模式适配

这个比较简单,首先改一下style,用DayNight的

<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">

然后在资源文件夹里,加一个文件夹values-night,里面放什么呢,就是你对应深色模式下的颜色配置文件colors.xml

其他图片文件资源其实也一样,建立一个mipmap-night文件夹放进去就好了。

APP主题切换工具

这个我自己上代码了


/**
 * 深色模式工具
 *
 * @author D10NG
 * @date on 2020/4/27 2:03 PM
 */
class NightModeUtils constructor(context: Context) {

    private val mSpf = context.getSharedPreferences("config_data", Context.MODE_PRIVATE)

    companion object {

        @Volatile
        private var INSTANCE: NightModeUtils? = null

        @JvmStatic
        fun getInstance(context: Context) : NightModeUtils =
            INSTANCE ?: synchronized(this) {
                INSTANCE ?: NightModeUtils(context).also {
                    INSTANCE = it
                }
            }

        private const val SPF_THEME_MODE = "theme_mode"
        private const val SPF_THEME_TIMER = "theme_timer"
    }

    /** 获取设置 */
    private fun getSpfThemeMode() : Int = mSpf.getInt(SPF_THEME_MODE, ThemeMode.MODE_FOLLOW_SYSTEM.intValue)

    /** 设置 */
    private fun setSpfThemeMode(mode: Int) {
        mSpf.edit().putInt(SPF_THEME_MODE, mode).apply()
    }

    /** 获取时间设置 */
    private fun getSpfThemeTimer() : String = mSpf.getString(SPF_THEME_TIMER, null)?: "18:00~08:00"

    /** 设置时间 */
    private fun setSpfThemeTimer(timer: String) {
        mSpf.edit().putString(SPF_THEME_TIMER, timer).apply()
    }

    /** 获取设置好的ThemeMode */
    fun getThemeMode(): ThemeMode = ThemeMode.parseOfInt(getSpfThemeMode())

    /** 设置模式 */
    fun setThemeMode(mode: ThemeMode) {
        setSpfThemeMode(mode.intValue)
    }

    /** 获取设置好的定时时间 */
    fun getThemeTime(): ThemeTime {
        val timeStr = getSpfThemeTimer()
        return ThemeTime(
            beginHour = timeStr.split("~")[0].split(":")[0].toInt(),
            beginMinute = timeStr.split("~")[0].split(":")[1].toInt(),
            endHour = timeStr.split("~")[1].split(":")[0].toInt(),
            endMinute = timeStr.split("~")[1].split(":")[1].toInt()
        )
    }

    /** 设置定时时间 */
    fun setThemeTime(time: ThemeTime) {
        setSpfThemeTimer(time.toTimerString())
    }

    /**
     * 应用存储的设置
     */
    fun applySetting() {
        // 检查主题
        val themeModeInt = getSpfThemeMode()
        val themeMode = ThemeMode.parseOfInt(themeModeInt)
        AppCompatDelegate.setDefaultNightMode(when(themeMode) {
            ThemeMode.MODE_ALWAYS_ON -> AppCompatDelegate.MODE_NIGHT_YES
            ThemeMode.MODE_ALWAYS_OFF -> AppCompatDelegate.MODE_NIGHT_NO
            ThemeMode.MODE_FOLLOW_SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
            else -> {
                val time = getThemeTime()

                val startTime = time.startTime.replace(":", ".").toFloat()
                val stopTime = time.stopTime.replace(":", ".").toFloat()
                val curTime = DateUtils.getCurDateStr("HH.mm").toFloat()
                if (stopTime > startTime) {
                    // 结束时间和开始时间都在同一天
                    if (curTime > startTime && curTime < stopTime) {
                        AppCompatDelegate.MODE_NIGHT_YES
                    } else {
                        AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
                    }
                } else {
                    // 结束时间在开始时间的后一天
                    if (curTime > startTime || curTime < stopTime) {
                        AppCompatDelegate.MODE_NIGHT_YES
                    } else {
                        AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
                    }
                }
            }
        })
    }
}

/**
 * 主题设置时间
 */
data class ThemeTime(
    // 开始小时
    val beginHour: Int,
    // 开始分钟
    val beginMinute: Int,
    // 结束小时
    val endHour: Int,
    // 结束分钟
    val endMinute: Int,
    // 开始时间
    var startTime: String = "00:00",
    // 结束时间
    var stopTime: String = "00:00"
) : Serializable {

    init {
        startTime = "${upTo2String(beginHour)}:${upTo2String(beginMinute)}"
        stopTime = "${upTo2String(endHour)}:${upTo2String(endMinute)}"
    }

    fun toTimerString() : String = "$startTime~$stopTime"

    // 保存成长度为2的字符串
    private fun upTo2String(value: Int): String {
        val valueStr = "$value"
        val result = StringBuilder()
        if (valueStr.length < 2) {
            for (i in 0 until 2 - valueStr.length) {
                result.append("0")
            }
        }
        result.append(valueStr)
        return result.toString().substring(result.length - 2)
    }
}

还有一个主题列表

/**
 * 主题开启模式
 * @author D10NG
 * @date on 2020/2/26 10:02 AM
 */
enum class ThemeMode(val intValue: Int, val stringValueId: Int) {
    MODE_ALWAYS_ON(0, R.string.theme_mode_0),
    MODE_ALWAYS_OFF(1, R.string.theme_mode_1),
    MODE_FOLLOW_SYSTEM(2, R.string.theme_mode_2),
    MODE_TIMER(3, R.string.theme_mode_3),;

    companion object {
        @JvmStatic
        fun parseOfString(context: Context, String: String): ThemeMode {
            return when(String) {
                context.resources.getString(MODE_ALWAYS_ON.stringValueId) -> MODE_ALWAYS_ON
                context.resources.getString(MODE_ALWAYS_OFF.stringValueId) -> MODE_ALWAYS_OFF
                context.resources.getString(MODE_TIMER.stringValueId) -> MODE_TIMER
                else -> MODE_FOLLOW_SYSTEM
            }
        }

        @JvmStatic
        fun parseOfInt(intValue: Int) : ThemeMode {
            return when(intValue) {
                MODE_ALWAYS_ON.intValue -> MODE_ALWAYS_ON
                MODE_ALWAYS_OFF.intValue -> MODE_ALWAYS_OFF
                MODE_TIMER.intValue -> MODE_TIMER
                else -> MODE_FOLLOW_SYSTEM
            }
        }
    }
}

字符串在这里

    <string name="theme_mode_0">一直开启</string>
    <string name="theme_mode_1">一直关闭</string>
    <string name="theme_mode_2">跟随系统设置</string>
    <string name="theme_mode_3">定时开启</string>

使用方法

首先在Aplication的onCreate中启动保存设置

    override fun onCreate() {
        super.onCreate()

        // 应用主题设置
        NightModeUtils.getInstance(this).applySetting()
    }

然后在你的Activity(最好有BaseActivity)中的onResume中同样加入启动设置

    override fun onResume() {
        super.onResume()
        NightModeUtils.getInstance(this).applySetting()
    }

以上就能保证页面能顺利切换主题了。

设置主题

NightModeUtils.getInstance(this).setThemeMode(ThemeMode.MODE_TIMER)

设置定时

val time = ThemeTime(
    endHour = 18,
    endMinute = 0,
    beginHour = 8,
    beginMinute = 0
)
NightModeUtils.getInstance(this).setThemeTime(time)

应用设置

NightModeUtils.getInstance(this).applySetting()

完事

你可能感兴趣的:(Android知识线)