O tema imersivo da barra de status do Android altera automaticamente o tema seguindo a cor de fundo da barra de status, e o tema da barra de status segue a cor de fundo da barra de status de forma adaptativa

1. Introdução ao modo de exibição da barra de status

O sistema Android oferece dois modos de exibição: modo claro e modo escuro

Modelo claro: a cor geral é brilhante, ou seja, o fundo é claro e o texto e outros conteúdos são escuros.

Modelo Escuro: A cor geral é mais escura, ou seja, o fundo é escuro e o texto e outros conteúdos são claros.

2. Defeitos na barra de status do Android

A cor do conteúdo da barra de status do Android (sem cor de fundo) é apenas preto e branco. Quando está no modo claro, é um tema preto, e quando está no modo escuro, é um tema branco. Claro, ter apenas duas cores não é uma falha.

Quando a cor de fundo da barra de status muda, precisamos definir manualmente o modo de exibição para alterar a cor do seu conteúdo. Isso é extremamente inconveniente, especialmente quando a cor de fundo da barra de status é gradiente.

Por exemplo:

Quando o WeChat é baixado, a cor de fundo da barra de status continua mudando, mas a cor do conteúdo não muda com o tempo, conforme mostrado na caixa vermelha na figura.

3. Ideação de solução 

Na verdade, a cor do conteúdo da barra de status é completamente adaptável. A lógica é muito simples. Quando o fundo estiver escuro, o conteúdo da barra de status ficará claro; quando o fundo estiver claro, o conteúdo da barra de status ficará escuro. Portanto, não há é uma ideia geral. Cada vez que a interface é desenhada:

  1. Obtenha pixels da barra de status

  2. Calcule seu valor médio de cor

  3. Determine se é uma cor brilhante

  4. Se for uma cor brilhante, defina-a para o modo claro, caso contrário, defina-a para o modo escuro.

4. Implementação de lógica de código específica

/**
     * 获取状态栏像素
     */
    private fun getStatusBarPixels(activity:Activity) = activity.window.decorView.let {
        it.isDrawingCacheEnabled = true
        it.buildDrawingCache()
        // 截屏
        val screenBitmap = it.getDrawingCache()
        val width = screenBitmap.width
        val height = BarUtils.getStatusBarHeight()
        val pixels = IntArray(width * height)
        // 获取状态栏区域像素
        screenBitmap.getPixels(pixels, 0, width, 0, 0, width, height)
        it.destroyDrawingCache()
        pixels
    }

    /**
     * 获取平均色值
     */
    fun getAvgColor(pixels: IntArray): Int {
        var r = 0L
        var g = 0L
        var b = 0L
        pixels.forEach {
            r += Color.red(it)
            g += Color.green(it)
            b += Color.blue(it)
        }
        r /= pixels.size
        g /= pixels.size
        b /= pixels.size
        return Color.rgb(r.toInt(), g.toInt(), b.toInt())
    }

O código acima obtém automaticamente o valor da cor da barra de status do celular e calcula o valor médio.

Em seguida, o método a seguir pode passar diretamente o valor da cor para alterar dinamicamente a cor do tema da barra de status.

/**
     * 是否为亮色
     * 可以单独传入 色值 判断是否为亮色
     */
    fun isLightColor(@ColorInt color: Int) =
        (computeLuminance(color) + 0.05).pow(2.0) > 0.15

    /**
     * 是否为亮色
     * 自动获取状态栏的色纸 判断是否为亮色
     */
    fun isLightColor(activity:Activity):Boolean{
        val pixels = getStatusBarPixels(activity)
        val color = getAvgColor(pixels)
        val computeColor = computeLuminance(color) + 0.05
        return (computeColor.pow(2.0) > 0.15)
    }

    /**
     * 颜色亮度
     */
    private fun computeLuminance(@ColorInt color: Int) =
        0.2126 * linearizeColorComponent(Color.red(color)) +
                0.7152 * linearizeColorComponent(Color.green(color)) +
                0.0722 * linearizeColorComponent(Color.blue(color))

    /**
     * 线性化颜色分量
     */
    private fun linearizeColorComponent(colorComponent: Int) = (colorComponent / 255.0).let {
        if (it <= 0.03928) it / 12.92 else ((it + 0.055) / 1.055).pow(2.4)
    }

5. Otimização de desempenho durante a aplicação

/**
     * 性能优化:单线程池,更新阻塞时只做最后一次更新
     */
    private val executor by lazy {
        object : ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, ArrayBlockingQueue(1)) {
            override fun execute(command: Runnable?) {
                queue.clear()
                super.execute(command)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        BarUtils.transparentStatusBar(this) // 需要沉浸状态栏,才能截屏至状态栏
        window.decorView.viewTreeObserver.addOnDrawListener(this)
    }

    override fun onDestroy() {
        window.decorView.viewTreeObserver.removeOnDrawListener(this)
        super.onDestroy()
    }

    override fun onDraw() {
        executor.execute {
            try {
                // 获取状态栏像素
                val pixels = getStatusBarPixels()
                // 计算平均色值
                val avgColor = getAvgColor(pixels)
                // 判断是否为亮色
                val isLight = isLightColor(avgColor)
                runOnUiThread {
                    // 设置 LightModel
                    if (!isDestroyed) BarUtils.setStatusBarLightMode(this, isLight)
                }
            } catch (_: Exception) {
            }
        }
    }

6. Exemplo geral de uso de código

class MainActivity : AppCompatActivity(), ViewTreeObserver.OnDrawListener {

    /**
     * 性能优化:单线程池,更新阻塞时只做最后一次更新
     */
    private val executor by lazy {
        object : ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, ArrayBlockingQueue(1)) {
            override fun execute(command: Runnable?) {
                queue.clear()
                super.execute(command)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        BarUtils.transparentStatusBar(this) // 需要沉浸状态栏,才能截屏至状态栏
        window.decorView.viewTreeObserver.addOnDrawListener(this)
    }

    override fun onDestroy() {
        window.decorView.viewTreeObserver.removeOnDrawListener(this)
        super.onDestroy()
    }

    override fun onDraw() {
        executor.execute {
            try {
                // 获取状态栏像素
                val pixels = getStatusBarPixels()
                // 计算平均色值
                val avgColor = getAvgColor(pixels)
                // 判断是否为亮色
                val isLight = isLightColor(avgColor)
                runOnUiThread {
                    // 设置 LightModel
                    if (!isDestroyed) BarUtils.setStatusBarLightMode(this, isLight)
                }
            } catch (_: Exception) {
            }
        }
    }

    /**
     * 获取状态栏像素
     */
    private fun getStatusBarPixels() = window.decorView.let {
        it.isDrawingCacheEnabled = true
        it.buildDrawingCache()
        // 截屏
        val screenBitmap = it.getDrawingCache()
        val width = screenBitmap.width
        val height = BarUtils.getStatusBarHeight()
        val pixels = IntArray(width * height)
        // 获取状态栏区域像素
        screenBitmap.getPixels(pixels, 0, width, 0, 0, width, height)
        it.destroyDrawingCache()
        pixels
    }

    /**
     * 获取平均色值
     */
    private fun getAvgColor(pixels: IntArray): Int {
        var r = 0L
        var g = 0L
        var b = 0L
        pixels.forEach {
            r += Color.red(it)
            g += Color.green(it)
            b += Color.blue(it)
        }
        r /= pixels.size
        g /= pixels.size
        b /= pixels.size
        return Color.rgb(r.toInt(), g.toInt(), b.toInt())
    }

    /**
     * 是否为亮色
     * 可以单独传入 色值 判断是否为亮色
     */
    fun isLightColor(@ColorInt color: Int) =
        (computeLuminance(color) + 0.05).pow(2.0) > 0.15

    /**
     * 是否为亮色
     * 自动获取状态栏的色纸 判断是否为亮色
     */
    fun isLightColor(activity:Activity):Boolean{
        val pixels = getStatusBarPixels(activity)
        val color = getAvgColor(pixels)
        val computeColor = computeLuminance(color) + 0.05
        return (computeColor.pow(2.0) > 0.15)
    }

    /**
     * 颜色亮度
     */
    private fun computeLuminance(@ColorInt color: Int) =
        0.2126 * linearizeColorComponent(Color.red(color)) +
                0.7152 * linearizeColorComponent(Color.green(color)) +
                0.0722 * linearizeColorComponent(Color.blue(color))

    /**
     * 线性化颜色分量
     */
    private fun linearizeColorComponent(colorComponent: Int) = (colorComponent / 255.0).let {
        if (it <= 0.03928) it / 12.92 else ((it + 0.055) / 1.055).pow(2.4)
    }
}

O acima é que o tema da barra de status muda automaticamente de acordo com a cor de fundo da barra de status. Você também pode passar o valor da cor para determinar se é uma cor brilhante e definir o tema da barra de status.

Acho que você gosta

Origin blog.csdn.net/weitao_666/article/details/132105650
Recomendado
Clasificación