利用Jetpack Compose實(shí)現(xiàn)主題切換功能
前言
新建的Compose項(xiàng)目默認(rèn)的 Material 主題為我們提供了一些顏色,但對(duì)我這種花里胡哨的人來(lái)說(shuō)根本不夠呀。 所以系統(tǒng)提供的主題不能滿足需求時(shí)候可以自己配置主題
compose 實(shí)現(xiàn)換膚很簡(jiǎn)單
之前xml方法可復(fù)雜了
通過(guò)LayoutInflater調(diào)用inflate方法加載XML布局,在inflate方法中有一個(gè)createViewFromTag,再根據(jù)LayoutInflater當(dāng)中Factory的接口類型(Factory or Factory2)調(diào)用CreateView方法加載,其中通過(guò)“name”可以得到加載的控件Tag,再通過(guò)AttributeSet得到控件的全部屬性最后再切換背景顏色

這是默認(rèn)的代碼,我們要改造一下
color.kt
先是用全局靜態(tài)變量寫(xiě)一套顏色變量
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,來(lái)標(biāo)明這個(gè)Color是有狀態(tài)的,如果狀態(tài)發(fā)生了改變,所有引用這個(gè)顏色的控件都發(fā)生了改變,都需要重新繪制!
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復(fù)制粘貼就行啦
接著定義兩套主題 白天和黑夜
你永遠(yuǎn)不懂我傷悲
像白天不懂夜的黑
//夜色主題
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,
)接著重要的一步來(lái)了,如何應(yīng)用這些顏色配色呢?
@Composable
fun AppTheme(
content: @Composable () -> Unit
)就是這樣
只需要在使用的時(shí)候把控件裝在里面就行了
應(yīng)用之前我們要判斷使用哪個(gè)主題
這里我用深色模式來(lái)演示
在Composable下可以用這行代碼判斷當(dāng)前系統(tǒng)處于深色模式
isSystemInDarkTheme()
var LocalAppColors = compositionLocalOf {
LightColorPalette
}
//主題配置單例
@Stable
object CustomTheme {
val colors: AppColors
@Composable
get() = LocalAppColors.current
//創(chuàng)建主題枚舉
enum class Theme {
Light, Dark
}
}關(guān)于compositionLocalOf
官方解釋如下: Compose 將數(shù)據(jù)通過(guò)組合樹(shù)顯式地通過(guò)參數(shù)傳遞給可組合函數(shù)。這通常是讓數(shù)據(jù)流過(guò)樹(shù)的最簡(jiǎn)單和最好的方法。
有時(shí),對(duì)于許多組件需要的數(shù)據(jù),或者當(dāng)組件需要在彼此之間傳遞數(shù)據(jù)但保持該實(shí)現(xiàn)細(xì)節(jié)私有時(shí),此模型可能很麻煩或分解。對(duì)于這些情況,CompositionLocal 可以用作讓數(shù)據(jù)流過(guò)組合的隱式方式。
CompositionLocal本質(zhì)上是分層的。當(dāng)CompositionLocal需要將的值限定為組合的特定子層次結(jié)構(gòu)時(shí),它們是有意義的。
必須創(chuàng)建一個(gè)CompositionLocal實(shí)例,該實(shí)例可以被消費(fèi)者靜態(tài)引用。CompositionLocal實(shí)例本身不持有任何數(shù)據(jù),可以將其視為傳遞到樹(shù)中的數(shù)據(jù)的類型安全標(biāo)識(shí)符。CompositionLocal工廠函數(shù)采用單個(gè)參數(shù):在CompositionLocal沒(méi)有提供程序的情況下使用a 的情況下創(chuàng)建默認(rèn)值的工廠。如果這是您不想處理的情況,則可以在此工廠中引發(fā)錯(cuò)誤。
在樹(shù)上的某個(gè)地方,CompositionLocalProvider可以使用一個(gè)組件,它為CompositionLocal. 這通常位于樹(shù)的“根”,但也可以在任何地方,也可以在多個(gè)位置使用以覆蓋子樹(shù)的提供值。 中間組件不需要知道該CompositionLocal值,并且可以對(duì)其具有零依賴關(guān)系
完整代碼
@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創(chuàng)建配置了給定持續(xù)時(shí)間、延遲和緩和曲線的效果 反正就是可以在換膚的時(shí)候不會(huì)一閃,會(huì)慢慢切換


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

到此這篇關(guān)于利用Jetpack Compose實(shí)現(xiàn)主題切換功能的文章就介紹到這了,更多相關(guān)Jetpack Compose內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文帶你了解Android中的網(wǎng)絡(luò)請(qǐng)求
安卓開(kāi)發(fā)網(wǎng)絡(luò)請(qǐng)求可謂是安卓開(kāi)發(fā)的靈魂,如果你不會(huì)網(wǎng)絡(luò)請(qǐng)求,那么你開(kāi)發(fā)的應(yīng)用軟件就是一具沒(méi)有靈魂的枯骨。本文主要為大家介紹的是Android的網(wǎng)絡(luò)請(qǐng)求,感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-11-11
Android最新版本開(kāi)發(fā)環(huán)境搭建圖文教程
這篇文章主要為大家詳細(xì)介紹了Android最新版本開(kāi)發(fā)環(huán)境搭建圖文教程,重點(diǎn)在于配置JDK,以及adt-bundle,感興趣的小伙伴們可以參考一下2016-07-07
Android將應(yīng)用調(diào)試log信息保存在SD卡的方法
Android將應(yīng)用調(diào)試log信息保存在SD卡的方法大家都知道嗎,下面腳本之家小編給大家分享Android將應(yīng)用調(diào)試log信息保存在SD卡的方法,感興趣的朋友參考下2016-04-04
Android自定義View原理(實(shí)戰(zhàn))
這篇文章主要介紹了Android自定義View原理,由于Android系統(tǒng)內(nèi)置的View不滿足我們的業(yè)務(wù)需求,變產(chǎn)生了需要自定義View的原因,關(guān)于自定義詳情,需要的小伙伴可以參考下面文章具體詳情2022-05-05
android判斷應(yīng)用是否已經(jīng)啟動(dòng)的實(shí)例
這篇文章主要介紹了android判斷應(yīng)用是否已經(jīng)啟動(dòng)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android實(shí)現(xiàn)繞球心旋轉(zhuǎn)的引導(dǎo)頁(yè)效果
本篇文章主要介紹了Android實(shí)現(xiàn)繞球心旋轉(zhuǎn)的引導(dǎo)頁(yè)效果,想要實(shí)現(xiàn)此效果的同學(xué)可以參考一下本文。2016-11-11
Android實(shí)現(xiàn)WebView點(diǎn)擊攔截跳轉(zhuǎn)原生
這篇文章主要介紹了Android實(shí)現(xiàn)WebView點(diǎn)擊攔截跳轉(zhuǎn)原生,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android直播系統(tǒng)平臺(tái)搭建之圖片實(shí)現(xiàn)陰影效果的方法小結(jié)
這篇文章主要介紹了Android直播系統(tǒng)平臺(tái)搭建, 圖片實(shí)現(xiàn)陰影效果的若干種方法,本文給大家?guī)?lái)三種方法,每種方法通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-08-08
Android提高之藍(lán)牙傳感應(yīng)用實(shí)例
這篇文章主要介紹了Android的藍(lán)牙傳感應(yīng)用實(shí)例,對(duì)于Android項(xiàng)目開(kāi)發(fā)來(lái)說(shuō)非常實(shí)用,需要的朋友可以參考下2014-08-08

