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

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


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

到此這篇關(guān)于利用Jetpack Compose實現(xiàn)主題切換功能的文章就介紹到這了,更多相關(guān)Jetpack Compose內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android利用ContentProvider初始化組件的踩坑記錄
做Android SDK開發(fā)的時候,一般我們會將初始化的方法封裝,然后讓調(diào)用SDK的開發(fā)者在Application的onCreate方法中進行初始化,下面這篇文章主要給大家介紹了關(guān)于Android利用ContentProvider初始化組件的踩坑記錄,需要的朋友可以參考下2022-04-04
Android7.0以上Uri轉(zhuǎn)路徑的方法實現(xiàn)(已驗證)
這篇文章主要介紹了Android7.0以上Uri轉(zhuǎn)路徑的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android?補間動畫及組合AnimationSet常用方法詳解
這篇文章主要為大家介紹了Android?補間動畫及組合AnimationSet常用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
Android 仿微博的點贊功能的實現(xiàn)原理(持續(xù)點贊再取消)
經(jīng)常玩微博的同志都知道,微博的持續(xù)點贊再取消功能,下面小編給大家?guī)砹薃ndroid 仿微博的點贊功能的實現(xiàn)原理(持續(xù)點贊再取消),感興趣的朋友跟隨腳本之家小編一起看看吧2018-03-03

