Compose'da özel tasarım sistemleri

Önerdiğimiz tasarım sistemimiz Material, jetpack Compose'u da Malzeme kullanmaya devam etmek zorunda kalmazsınız. Malzeme üretildi Bu yüzden, kendi tasarım sisteminizi yalnızca herkese açık API'lerde aynı şekilde yürütülür.

Uygulayabileceğiniz çeşitli yaklaşımlar vardır:

Ayrıca, Materyal bileşenlerini özel bir tasarımla kullanmaya devam etmek de isteyebilirsiniz. bahsedeceğim. Bunu yapmak mümkündür ancak bu yaklaşıma uymak için aklınızda bulundurmanız gereken ne kadar iyi karşıladığını göreceksiniz.

MaterialTheme tarafından kullanılan alt düzey yapılar ve API'ler hakkında daha fazla bilgi edinmek için ve özel tasarım sistemleri için Oluşturma'da temanın anatomisi rehberine göz atın.

Malzeme Temasını Uzatma

Materyal öğeleri yakından modelleri oluşturma Malzeme Teması uygulayın. Ancak, renk, yazı ve şekil setlerini daha fazla ek bileşenle değerler.

En basit yaklaşım, uzantı özellikleri eklemektir:

// Use with MaterialTheme.colors.snackbarAction
val Colors.snackbarAction: Color
    get() = if (isLight) Red300 else Red700

// Use with MaterialTheme.typography.textFieldInput
val Typography.textFieldInput: TextStyle
    get() = TextStyle(/* ... */)

// Use with MaterialTheme.shapes.card
val Shapes.card: Shape
    get() = RoundedCornerShape(size = 20.dp)

Bu, MaterialTheme kullanım API'leriyle tutarlılık sağlar. Bu duruma bir örnek Compose'un kendisi tarafından tanımlanan primarySurface bağlı olarak primary ile surface arasında bir proxy görevi görür Colors.isLight.

Bir diğer yaklaşım da “sarmalayan” MaterialTheme ve değer.

tertiary ve onTertiary olmak üzere iki ilave renk eklemek istediğinizi varsayalım Ancak mevcut Malzeme renklerini korur:

@Immutable
data class ExtendedColors(
    val tertiary: Color,
    val onTertiary: Color
)

val LocalExtendedColors = staticCompositionLocalOf {
    ExtendedColors(
        tertiary = Color.Unspecified,
        onTertiary = Color.Unspecified
    )
}

@Composable
fun ExtendedTheme(
    /* ... */
    content: @Composable () -> Unit
) {
    val extendedColors = ExtendedColors(
        tertiary = Color(0xFFA8EFF0),
        onTertiary = Color(0xFF002021)
    )
    CompositionLocalProvider(LocalExtendedColors provides extendedColors) {
        MaterialTheme(
            /* colors = ..., typography = ..., shapes = ... */
            content = content
        )
    }
}

// Use with eg. ExtendedTheme.colors.tertiary
object ExtendedTheme {
    val colors: ExtendedColors
        @Composable
        get() = LocalExtendedColors.current
}

Bu, MaterialTheme kullanım API'lerine benzer. Ayrıca birden fazla temayı destekler. ExtendedTheme öğelerini MaterialTheme ile aynı şekilde iç içe yerleştirebilirsiniz.

Materyal bileşenlerini kullanma

Materyal Teması genişletilirken mevcut MaterialTheme değerleri korunur Malzeme bileşenlerinin varsayılan değerleri hâlâ makul.

Bileşenlerde genişletilmiş değerleri kullanmak istiyorsanız bunları kendi öğenize sarmalayın. composable işlevleri, değiştirmek istediğiniz değerleri doğrudan ayarlama ve Örneğin, diğerlerini kapsayıcı composable'a parametre olarak sunma:

@Composable
fun ExtendedButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            containerColor = ExtendedTheme.colors.tertiary,
            contentColor = ExtendedTheme.colors.onTertiary
            /* Other colors use values from MaterialTheme */
        ),
        onClick = onClick,
        modifier = modifier,
        content = content
    )
}

Daha sonra, Button kullanımlarını ExtendedButton ile değiştirirsiniz; burada: uygun olmalıdır.

@Composable
fun ExtendedApp() {
    ExtendedTheme {
        /*...*/
        ExtendedButton(onClick = { /* ... */ }) {
            /* ... */
        }
    }
}

Material sistemlerini değiştirme

Malzeme Temalarını uzatmak yerine, örneğin bir veya daha fazla sistemleri (Colors, Typography veya Shapes) özel bir uygulamayla, diğerlerini korur.

Tip ve şekil sistemlerini renginizi korurken değiştirmek istediğinizi varsayalım sistem:

@Immutable
data class ReplacementTypography(
    val body: TextStyle,
    val title: TextStyle
)

@Immutable
data class ReplacementShapes(
    val component: Shape,
    val surface: Shape
)

val LocalReplacementTypography = staticCompositionLocalOf {
    ReplacementTypography(
        body = TextStyle.Default,
        title = TextStyle.Default
    )
}
val LocalReplacementShapes = staticCompositionLocalOf {
    ReplacementShapes(
        component = RoundedCornerShape(ZeroCornerSize),
        surface = RoundedCornerShape(ZeroCornerSize)
    )
}

@Composable
fun ReplacementTheme(
    /* ... */
    content: @Composable () -> Unit
) {
    val replacementTypography = ReplacementTypography(
        body = TextStyle(fontSize = 16.sp),
        title = TextStyle(fontSize = 32.sp)
    )
    val replacementShapes = ReplacementShapes(
        component = RoundedCornerShape(percent = 50),
        surface = RoundedCornerShape(size = 40.dp)
    )
    CompositionLocalProvider(
        LocalReplacementTypography provides replacementTypography,
        LocalReplacementShapes provides replacementShapes
    ) {
        MaterialTheme(
            /* colors = ... */
            content = content
        )
    }
}

// Use with eg. ReplacementTheme.typography.body
object ReplacementTheme {
    val typography: ReplacementTypography
        @Composable
        get() = LocalReplacementTypography.current
    val shapes: ReplacementShapes
        @Composable
        get() = LocalReplacementShapes.current
}

Materyal bileşenlerini kullanma

Bir veya daha fazla MaterialTheme sistemi Material kullanılarak değiştirildiğinde olduğu gibi, istenmeyen Materyal renk, tür veya şekil değerlerine neden olabilir.

Bileşenlerde ikame değerler kullanmak istiyorsanız bunları kendi bileşenlerinize sarmalayın. composable işlevleri, ilgili sistem için değerleri doğrudan ayarlama ve Bu işlem, başkalarını kapsayıcı composable'a parametre olarak gösterir.

@Composable
fun ReplacementButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        shape = ReplacementTheme.shapes.component,
        onClick = onClick,
        modifier = modifier,
        content = {
            ProvideTextStyle(
                value = ReplacementTheme.typography.body
            ) {
                content()
            }
        }
    )
}

Daha sonra, Button kullanımlarını ReplacementButton ile değiştirirsiniz; burada: uygun olmalıdır.

@Composable
fun ReplacementApp() {
    ReplacementTheme {
        /*...*/
        ReplacementButton(onClick = { /* ... */ }) {
            /* ... */
        }
    }
}

Tamamen özel bir tasarım sistemini uygulamaya geçirme

Materyal Temaları'nı tamamen özel bir tasarım sistemiyle değiştirmek isteyebilirsiniz. MaterialTheme kapsamında aşağıdaki sistemlerin sunulduğunu göz önünde bulundurun:

  • Colors, Typography ve Shapes: Malzeme teması sistemleri
  • ContentAlpha: Text ve Icon'da vurguyu göstermek için opaklık seviyeleri
  • TextSelectionColors: Metin seçimi için Text ve TextField
  • Ripple ve RippleTheme: Indication öğesinin materyal uygulaması

Materyal bileşenleri kullanmaya devam etmek istiyorsanız bazı bileşenleri özel temalarınızda veya temalarınızda kullanabilir ya da bileşenlerine ayırmanızı sağlar.

Ne var ki, tasarım sistemleri Materyal’in dayandığı kavramlarla sınırlı değildir. Siz mevcut sistemleri değiştirebilir ve yeni sınıflarla tamamen yenilerini tanıtabilir. kullanarak diğer kavramları temalarla uyumlu hale getirin.

Aşağıdaki kodda, renk geçişleri içeren özel bir renk sistemini modelliyoruz (List<Color>), bir tür sistemi ekleyin, yeni bir yükselti sistemi tanıtın, ve MaterialTheme tarafından sağlanan diğer sistemleri hariç tutun:

@Immutable
data class CustomColors(
    val content: Color,
    val component: Color,
    val background: List<Color>
)

@Immutable
data class CustomTypography(
    val body: TextStyle,
    val title: TextStyle
)

@Immutable
data class CustomElevation(
    val default: Dp,
    val pressed: Dp
)

val LocalCustomColors = staticCompositionLocalOf {
    CustomColors(
        content = Color.Unspecified,
        component = Color.Unspecified,
        background = emptyList()
    )
}
val LocalCustomTypography = staticCompositionLocalOf {
    CustomTypography(
        body = TextStyle.Default,
        title = TextStyle.Default
    )
}
val LocalCustomElevation = staticCompositionLocalOf {
    CustomElevation(
        default = Dp.Unspecified,
        pressed = Dp.Unspecified
    )
}

@Composable
fun CustomTheme(
    /* ... */
    content: @Composable () -> Unit
) {
    val customColors = CustomColors(
        content = Color(0xFFDD0D3C),
        component = Color(0xFFC20029),
        background = listOf(Color.White, Color(0xFFF8BBD0))
    )
    val customTypography = CustomTypography(
        body = TextStyle(fontSize = 16.sp),
        title = TextStyle(fontSize = 32.sp)
    )
    val customElevation = CustomElevation(
        default = 4.dp,
        pressed = 8.dp
    )
    CompositionLocalProvider(
        LocalCustomColors provides customColors,
        LocalCustomTypography provides customTypography,
        LocalCustomElevation provides customElevation,
        content = content
    )
}

// Use with eg. CustomTheme.elevation.small
object CustomTheme {
    val colors: CustomColors
        @Composable
        get() = LocalCustomColors.current
    val typography: CustomTypography
        @Composable
        get() = LocalCustomTypography.current
    val elevation: CustomElevation
        @Composable
        get() = LocalCustomElevation.current
}

Materyal bileşenlerini kullanma

MaterialTheme mevcut olmadığında, Materyal bileşenleri olduğu gibi kullanıldığında istenmeyen Malzeme rengi, türü, şekil değerleri ve gösterge davranışında hata meydana gelebilir.

Bileşenlerde özel değerler kullanmak isterseniz bunları kendi composable'ınıza sarmalayın. fonksiyonlarını kullanarak, alakalı sisteme yönelik değerleri doğrudan ayarlayarak ve diğerlerini, kapsayıcı composable'a parametre olarak alır.

Özel temanızda belirlediğiniz değerlere erişmenizi öneririz. Alternatif olarak temanız Color, TextStyle, Shape veya başka sistemler sağlamıyorsa, bunları sabit bir şekilde kodlayabilirsiniz.

@Composable
fun CustomButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            containerColor = CustomTheme.colors.component,
            contentColor = CustomTheme.colors.content,
            disabledContainerColor = CustomTheme.colors.content
                .copy(alpha = 0.12f)
                .compositeOver(CustomTheme.colors.component),
            disabledContentColor = CustomTheme.colors.content
                .copy(alpha = ContentAlpha.disabled)
        ),
        shape = ButtonShape,
        elevation = ButtonDefaults.elevatedButtonElevation(
            defaultElevation = CustomTheme.elevation.default,
            pressedElevation = CustomTheme.elevation.pressed
            /* disabledElevation = 0.dp */
        ),
        onClick = onClick,
        modifier = modifier,
        content = {
            ProvideTextStyle(
                value = CustomTheme.typography.body
            ) {
                content()
            }
        }
    )
}

val ButtonShape = RoundedCornerShape(percent = 50)

Renk geçişlerini temsil etmek için List<Color> gibi yeni sınıf türleri eklediyseniz bileşenleri sarmalamak yerine sıfırdan uygulamanız daha iyi olabilir. Örnek olarak, JetsnackButton 10 kat daha fazla.

ziyaret edin.