利用Jetpack Compose实现主题切换功能

 更新时间:2022年01月27日 10:33:11   作者:九狼  
这篇文章主要介绍了如何利用Android中的Jetpack Compose实现主题切换功能,文中的示例代码讲解详细,对我们学习有一定帮助,需要的可以参考一下

前言

新建的Compose项目默认的 Material 主题为我们提供了一些颜色,但对我这种花里胡哨的人来说根本不够呀。 所以系统提供的主题不能满足需求时候可以自己配置主题

compose 实现换肤很简单

之前xml方法可复杂了

通过LayoutInflater调用inflate方法加载XML布局,在inflate方法中有一个createViewFromTag,再根据LayoutInflater当中Factory的接口类型(Factory or Factory2)调用CreateView方法加载,其中通过“name”可以得到加载的控件Tag,再通过AttributeSet得到控件的全部属性最后再切换背景颜色

这是默认的代码,我们要改造一下

color.kt

先是用全局静态变量写一套颜色变量

val statusBarColorLight = Color(0xFFFFFFFF)
val statusBarColorDark = Color(0xFF1C1C28)

val backgroundColorLight = Color(0xFFF2F2F6)
val backgroundColorDark = Color(0xFF1C1C28)

val textPrimaryLight = Color(0xFF333333)
val textPrimaryDark = Color(0xFFE8E8F0)

val textSecondaryLight = Color(0xFF999999)
val textSecondaryDark = Color(0xFF999999)

...此处省略500字 哈哈

Theme.kt

定义各种各样的颜色名称

@Stable
class AppColors(
    statusBarColor: Color,
    themeUi: Color,
    background: Color,
    listItem: Color,
    divider: Color,
    textPrimary: Color,
    textSecondary: Color,
    mainColor: Color,
    card: Color,
    icon: Color,
    info: Color,
    warn: Color,
    success: Color,
    error: Color,
    primaryBtnBg: Color,
    secondBtnBg: Color,
    hot: Color,
    placeholder: Color,
)

接着引入mutableStateOf,来标明这个Color是有状态的,如果状态发生了改变,所有引用这个颜色的控件都发生了改变,都需要重新绘制!

var statusBarColor: Color by mutableStateOf(statusBarColor)
    internal set
var themeUi: Color by mutableStateOf(themeUi)
    internal set
var background: Color by mutableStateOf(background)
    private set
var listItem: Color by mutableStateOf(listItem)
    private set
var divider: Color by mutableStateOf(divider)
    private set
var textPrimary: Color by mutableStateOf(textPrimary)
    internal set
var textSecondary: Color by mutableStateOf(textSecondary)
    private set
var mainColor: Color by mutableStateOf(mainColor)
    internal set
var card: Color by mutableStateOf(card)
    private set
var icon: Color by mutableStateOf(icon)
    private set
var info: Color by mutableStateOf(info)
    private set
var warn: Color by mutableStateOf(warn)
    private set
var success: Color by mutableStateOf(success)
    private set
var error: Color by mutableStateOf(error)
    private set
var primaryBtnBg: Color by mutableStateOf(primaryBtnBg)
    internal set
var secondBtnBg: Color by mutableStateOf(secondBtnBg)
    private set
var hot: Color by mutableStateOf(hot)
    private set
var placeholder: Color by mutableStateOf(placeholder)
    private set

复制粘贴就行啦

接着定义两套主题 白天和黑夜

你永远不懂我伤悲

像白天不懂夜的黑

//夜色主题
private val DarkColorPalette = AppColors(
    statusBarColor = statusBarColorDark,
    themeUi = themeColor,
    background = backgroundColorDark,
    listItem = listItemDark,
    divider = dividerDark,
    textPrimary = textPrimaryDark,
    textSecondary = textSecondaryDark,
    mainColor = black3,
    card = black3,
    icon = grey1,
    info = info,
    warn = warn,
    success = green3,
    error = red2,
    primaryBtnBg = backgroundColorDark,
    secondBtnBg = black3,
    hot = red,
    placeholder = grey1,
)

//白天主题
private val LightColorPalette = AppColors(
    statusBarColor = statusBarColorLight,
    themeUi = themeColor,
    background = backgroundColorLight,
    listItem = listItemLight,
    divider = dividerLight,
    textPrimary = textPrimaryLight,
    textSecondary = textSecondaryLight,
    mainColor = white,
    card = white1,
    icon = inonGary,
    info = info,
    warn = warn,
    success = green3,
    error = red2,
    primaryBtnBg = themeColor,
    secondBtnBg = white3,
    hot = red,
    placeholder = white3,
)

接着重要的一步来了,如何应用这些颜色配色呢?

@Composable
fun AppTheme(
    content: @Composable () -> Unit
)

就是这样

只需要在使用的时候把控件装在里面就行了

应用之前我们要判断使用哪个主题

这里我用深色模式来演示

在Composable下可以用这行代码判断当前系统处于深色模式

isSystemInDarkTheme()
var LocalAppColors = compositionLocalOf {
    LightColorPalette
}
//主题配置单例
@Stable
object CustomTheme {
    val colors: AppColors
        @Composable
        get() = LocalAppColors.current

  //创建主题枚举
    enum class Theme {
        Light, Dark
    }
}

关于compositionLocalOf

官方解释如下: Compose 将数据通过组合树显式地通过参数传递给可组合函数。这通常是让数据流过树的最简单和最好的方法。

有时,对于许多组件需要的数据,或者当组件需要在彼此之间传递数据但保持该实现细节私有时,此模型可能很麻烦或分解。对于这些情况,CompositionLocal 可以用作让数据流过组合的隐式方式。

CompositionLocal本质上是分层的。当CompositionLocal需要将的值限定为组合的特定子层次结构时,它们是有意义的。

必须创建一个CompositionLocal实例,该实例可以被消费者静态引用。CompositionLocal实例本身不持有任何数据,可以将其视为传递到树中的数据的类型安全标识符。CompositionLocal工厂函数采用单个参数:在CompositionLocal没有提供程序的情况下使用a 的情况下创建默认值的工厂。如果这是您不想处理的情况,则可以在此工厂中引发错误。

在树上的某个地方,CompositionLocalProvider可以使用一个组件,它为CompositionLocal. 这通常位于树的“根”,但也可以在任何地方,也可以在多个位置使用以覆盖子树的提供值。 中间组件不需要知道该CompositionLocal值,并且可以对其具有零依赖关系

完整代码

@Composable
fun AppTheme(
    isDark :Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {

    val targetColors = if (isDark) DarkColorPalette else LightColorPalette

    val statusBarColor = animateColorAsState(targetColors.statusBarColor, TweenSpec(600))
    val themeUi = animateColorAsState(targetColors.themeUi, TweenSpec(600))
    val background = animateColorAsState(targetColors.background, TweenSpec(600))
    val listItem = animateColorAsState(targetColors.listItem, TweenSpec(600))
    val divider = animateColorAsState(targetColors.divider, TweenSpec(600))
    val textPrimary = animateColorAsState(targetColors.textPrimary, TweenSpec(600))
    val textSecondary = animateColorAsState(targetColors.textSecondary, TweenSpec(600))
    val mainColor = animateColorAsState(targetColors.mainColor, TweenSpec(600))
    val card = animateColorAsState(targetColors.card, TweenSpec(600))
    val icon = animateColorAsState(targetColors.icon, TweenSpec(600))
    val info = animateColorAsState(targetColors.info, TweenSpec(600))
    val warn = animateColorAsState(targetColors.warn, TweenSpec(600))
    val success = animateColorAsState(targetColors.success, TweenSpec(600))
    val error = animateColorAsState(targetColors.error, TweenSpec(600))
    val primaryBtnBg = animateColorAsState(targetColors.primaryBtnBg, TweenSpec(600))
    val secondBtnBg = animateColorAsState(targetColors.secondBtnBg, TweenSpec(600))
    val hot = animateColorAsState(targetColors.hot, TweenSpec(600))
    val placeholder = animateColorAsState(targetColors.placeholder, TweenSpec(600))

    val appColors = AppColors(
        statusBarColor = statusBarColor.value,
        themeUi = themeUi.value,
        background = background.value,
        listItem = listItem.value,
        divider = divider.value,
        textPrimary = textPrimary.value,
        textSecondary = textSecondary.value,
        mainColor = mainColor.value,
        card = card.value,
        icon = icon.value,
        primaryBtnBg = primaryBtnBg.value,
        secondBtnBg = secondBtnBg.value,
        info = info.value,
        warn = warn.value,
        success = success.value,
        error = error.value,
        hot = hot.value,
        placeholder = placeholder.value
    )

    ProvideWindowInsets {
        CompositionLocalProvider(LocalAppColors provides appColors) {
            MaterialTheme(
                shapes = shapes
            ) {
                ProvideWindowInsets(content = content)
            }
        }
    }
}

用TweenSpec创建配置了给定持续时间、延迟和缓和曲线的效果 反正就是可以在换肤的时候不会一闪,会慢慢切换

最后放在AppTheme下面使用就可以啦

到此这篇关于利用Jetpack Compose实现主题切换功能的文章就介绍到这了,更多相关Jetpack Compose内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详谈android界面之间数据的传递

    详谈android界面之间数据的传递

    下面小编就为大家带来一篇详谈android界面之间数据的传递。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • 一文带你了解Android中的网络请求

    一文带你了解Android中的网络请求

    安卓开发网络请求可谓是安卓开发的灵魂,如果你不会网络请求,那么你开发的应用软件就是一具没有灵魂的枯骨。本文主要为大家介绍的是Android的网络请求,感兴趣的可以跟随小编一起学习一下
    2022-11-11
  • Android最新版本开发环境搭建图文教程

    Android最新版本开发环境搭建图文教程

    这篇文章主要为大家详细介绍了Android最新版本开发环境搭建图文教程,重点在于配置JDK,以及adt-bundle,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Android将应用调试log信息保存在SD卡的方法

    Android将应用调试log信息保存在SD卡的方法

    Android将应用调试log信息保存在SD卡的方法大家都知道吗,下面脚本之家小编给大家分享Android将应用调试log信息保存在SD卡的方法,感兴趣的朋友参考下
    2016-04-04
  • Android自定义View原理(实战)

    Android自定义View原理(实战)

    这篇文章主要介绍了Android自定义View原理,由于Android系统内置的View不满足我们的业务需求,变产生了需要自定义View的原因,关于自定义详情,需要的小伙伴可以参考下面文章具体详情
    2022-05-05
  • android判断应用是否已经启动的实例

    android判断应用是否已经启动的实例

    这篇文章主要介绍了android判断应用是否已经启动的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • Android实现绕球心旋转的引导页效果

    Android实现绕球心旋转的引导页效果

    本篇文章主要介绍了Android实现绕球心旋转的引导页效果,想要实现此效果的同学可以参考一下本文。
    2016-11-11
  • Android实现WebView点击拦截跳转原生

    Android实现WebView点击拦截跳转原生

    这篇文章主要介绍了Android实现WebView点击拦截跳转原生,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • Android直播系统平台搭建之图片实现阴影效果的方法小结

    Android直播系统平台搭建之图片实现阴影效果的方法小结

    这篇文章主要介绍了Android直播系统平台搭建, 图片实现阴影效果的若干种方法,本文给大家带来三种方法,每种方法通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-08-08
  • Android提高之蓝牙传感应用实例

    Android提高之蓝牙传感应用实例

    这篇文章主要介绍了Android的蓝牙传感应用实例,对于Android项目开发来说非常实用,需要的朋友可以参考下
    2014-08-08

最新评论