Compose 主題剖析

Jetpack Compose 的主題是由多個較低層級的建構和相關 API 組成。您可以在 MaterialTheme原始碼中查看這些套件,也可在自訂設計系統中套用。

主題系統類別

主題通常由許多系統組成,而這些系統會將常見的視覺和行為概念分組。這些系統可以使用具有主題值的類別建模。

舉例來說,MaterialTheme 包含 Colors (色彩系統)、Typography (字型系統),以及 Shapes (形狀系統)。

@Immutable
data class ColorSystem(
    val color: Color,
    val gradient: List<Color>
    /* ... */
)

@Immutable
data class TypographySystem(
    val fontFamily: FontFamily,
    val textStyle: TextStyle
)
/* ... */

@Immutable
data class CustomSystem(
    val value1: Int,
    val value2: String
    /* ... */
)

/* ... */

主題系統組合本機值

主題系統類別會以隱含形式提供給組合樹,做為 CompositionLocal 執行個體。這可讓可組合函式中的主題值採用靜態參照。

如要進一步瞭解 CompositionLocal,請參閱「使用 CompositionLocal 的本機範圍資料」指南

val LocalColorSystem = staticCompositionLocalOf {
    ColorSystem(
        color = Color.Unspecified,
        gradient = emptyList()
    )
}

val LocalTypographySystem = staticCompositionLocalOf {
    TypographySystem(
        fontFamily = FontFamily.Default,
        textStyle = TextStyle.Default
    )
}

val LocalCustomSystem = staticCompositionLocalOf {
    CustomSystem(
        value1 = 0,
        value2 = ""
    )
}

/* ... */

主題功能

主題函式為進入點和主要 API,可建構主題系統 CompositionLocal 的執行個體 (使用任何邏輯的必要實際值),提供給具有 CompositionLocalProvider 的組合樹。content 參數允許巢狀的可組合值存取階層相對的主題值。

@Composable
fun Theme(
    /* ... */
    content: @Composable () -> Unit
) {
    val colorSystem = ColorSystem(
        color = Color(0xFF3DDC84),
        gradient = listOf(Color.White, Color(0xFFD7EFFF))
    )
    val typographySystem = TypographySystem(
        fontFamily = FontFamily.Monospace,
        textStyle = TextStyle(fontSize = 18.sp)
    )
    val customSystem = CustomSystem(
        value1 = 1000,
        value2 = "Custom system"
    )
    /* ... */
    CompositionLocalProvider(
        LocalColorSystem provides colorSystem,
        LocalTypographySystem provides typographySystem,
        LocalCustomSystem provides customSystem,
        /* ... */
        content = content
    )
}

主題物件

若要存取主題系統,可以使用具有便利屬性的物件。為保持一致性,物件通常會採用與主題函式相同的名稱。屬性只會取得本機目前的組合。

// Use with eg. Theme.colorSystem.color
object Theme {
    val colorSystem: ColorSystem
        @Composable
        get() = LocalColorSystem.current
    val typographySystem: TypographySystem
        @Composable
        get() = LocalTypographySystem.current
    val customSystem: CustomSystem
        @Composable
        get() = LocalCustomSystem.current
    /* ... */
}