利用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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!