利用Jetpack Compose实现主题切换功能
作者:九狼 发布时间:2023-03-10 03:14:37
前言
新建的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下面使用就可以啦
来源:https://juejin.cn/post/7057418707357663246
猜你喜欢
- 一、ConcurrentBag类ConcurrentBag<T>对外提供的方法没有List<T>那么多,但是同样有E
- 普通 jar 包的导出1.点击 file 中的project.structor=>选择Artifacts=>+=>选择 j
- 由于最近想要阅读下JDK1.8 中HashMap的具体实现,但是由于HashMap的实现中用到了红黑树,所以我觉得有必要先复习下红黑树的相关
- Unity脚本中枚举类型在inspector面板中文显示,供大家参考,具体内容如下效果:工具脚本:ChineseEnumTool.csusi
- 这篇文章主要介绍了Java集合使用 Iterator 删除元素,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,
- 这篇文章主要介绍了java实现上传文件类型检测过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 马云说:“未来最大的资源就是数据,不参与大数据十年后一定会后悔。”毕竟出自wuli马大大之口,今年二月份我开始了学习大数据的道路,直到现在对
- 对于数据的访问来说,肯定是在有缓存的情况下运行快一些。对于Hibernate这种与数据库结合紧密的框架来说,在调用数据的时候肯定会有缓存的出
- ListView,就如其名,是用来显示列表的一种View,而RecycleView,是其的加强版,今天带来的是这两个几乎具有相同的功能的对比
- 在使用struts多模块的,找到一些小技巧和经验,与大家分享一下。 关于多module的配置就不说了,只需要用不同的config
- 下载maven 解压路径: 打开环境变量:右键此电脑-属性-高级系统设置-高级-环境变量添加以下系统变量:测试:win+
- 分页插件  MP中自带了分页插件的功能,只需要在配置类中进行简单的配置即可使用分页的相关功能。分页插件常
- 我们用一个简单的例子,来说明一下这种消息传递的机制。有一家三口,妈妈负责做饭,爸爸和孩子负责吃。。。将这三个人,想象成三个类。妈妈有一个方法
- 在某种场景下,可能我们需要获取app的图标名称和启动图片的名称。比如说app在前台时,收到了远程通知但是通知栏是不会有通知提醒的,这时我想做
- 本文实例为大家分享了C#实现银行家算法的具体代码,供大家参考,具体内容如下1.死锁死锁,顾名思义,是一种锁住不可自行解开的死局。在操作系统中
- 定时任务技术趋势简介:定时任务是每个业务常见的需求,比如每分钟扫描超时支付的订单,每小时清理一次数据库历史数据,每天统计前一天的数据并生成报
- SSM在Controller中添加事务管理本人使用:集成开发环境:idea项目管理工具:maven数据库:oracle框架:Spring+S
- AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合。其实AsyncTask并不是那么好,甚至有些糟糕。本文
- 切面编程听起来可能有点陌生,不过现在越来越多的开发团队正在用上这种技术。先说熟悉的面向对象编程 OOP,通常都是用各种对象/模块来负责具体的
- 本文主要对SpringBoot2.x参数校验进行简单总结,其中SpringBoot使用的2.4.5版本。一、引入依赖<dependen