Podstawy stylów

Style w aplikacji możesz zastosować na 3 sposoby:

  1. Użyj bezpośrednio w istniejących komponentach, które udostępniają Style parametr.
  2. Zastosuj styl za pomocą Modifier.styleable w kompozycjach układu , które nie akceptują parametru Style.
  3. W swoim niestandardowym systemie projektowania użyj Modifier.styleable{} i udostępnij parametr stylu w swoich komponentach.

Dostępne właściwości w stylach

Style obsługują wiele tych samych właściwości co modyfikatory, ale nie wszystko, co jest modyfikatorem, można odtworzyć za pomocą stylu. W przypadku niektórych zachowań, takich jak interakcje, rysowanie niestandardowe czy układanie właściwości w stos, nadal potrzebujesz modyfikatorów.

Grupowanie Właściwości Dziedziczone przez elementy podrzędne
Układ i rozmiar
Dopełnienie contentPadding (wewnętrzne) i externalPadding (zewnętrzne). Dostępne w wariantach kierunkowych, poziomych, pionowych i z wszystkich stron. Nie
Wymiary fillWidth/Height/Size() oraz width, height i size (obsługuje ułamki Dp, DpSize lub Float). Nie
Pozycjonowanie Przesunięcia left/top/right/bottom. Nie
Wygląd
Ładowanie background i foreground (obsługuje Color lub Brush). Nie
Obramowanie borderWidth, borderColor i borderBrush. Nie
Kształt shape Nie – ale używany w połączeniu z innymi właściwościami. clip i border używają tego zdefiniowanego kształtu.
Cienie dropShadow, innerShadow Nie
Transformacje
Ruch przestrzenny warstwy graficznej translationX, translationY, scaleX/Y, rotationX/Y/Z Nie
Kontrola alpha, zIndex (kolejność układania w stos) i transformOrigin (punkt obrotu) Nie
Typografia
Styl textStyle, fontSize, fontWeight, fontStyle i fontFamily Tak
Kolorystyka contentColor i contentBrush. Jest też używany do stylizowania ikon. Tak
Akapit lineHeight, letterSpacing, textAlign, textDirection, lineBreak i hyphens. Tak
Dekoracje textDecoration, textIndent i baselineShift. Tak

Używanie stylów bezpośrednio w komponentach z parametrami stylu

Komponenty, które udostępniają parametr Style, umożliwiają ustawienie ich stylu:

BaseButton(
    onClick = { },
    style = { }
) {
    BaseText("Click me")
}

W lambdzie stylu możesz ustawić różne właściwości, takie jak externalPadding lub background:

BaseButton(
    onClick = { },
    style = { background(Color.Blue) }
) {
    BaseText("Click me")
}

Pełną listę obsługiwanych właściwości znajdziesz w sekcji Dostępne właściwości w stylach.

Stosowanie stylów za pomocą modyfikatorów w przypadku komponentów bez istniejącego parametru

W przypadku komponentów, które nie mają wbudowanego parametru stylu, możesz nadal stosować style za pomocą modyfikatora styleable. To podejście jest też przydatne podczas tworzenia własnych komponentów niestandardowych.

Row(
    modifier = Modifier.styleable { }
) {
    BaseText("Content")
}

Podobnie jak w przypadku parametru style w lambdzie możesz uwzględnić właściwości takie jak background lub padding.

Row(
    modifier = Modifier.styleable {
        background(Color.Blue)
    }
) {
    BaseText("Content")
}

Wiele połączonych modyfikatorów Modifier.styleable jest addytywnych w przypadku właściwości niedziedziczonych w zastosowanej kompozycji, podobnie jak w przypadku wielu modyfikatorów definiujących te same właściwości. W przypadku właściwości dziedziczonych są one zastępowane, a wartości ustawia ostatni modyfikator styleable w łańcuchu.

Gdy używasz Modifier.styleable, możesz też utworzyć i podać StyleState, który będzie używany z modyfikatorem do stosowania stylów opartych na stanie. Więcej informacji znajdziesz w artykule Stan i animacje ze stylami.

Definiowanie samodzielnego stylu

Aby można było ponownie używać stylu, możesz zdefiniować samodzielny styl:

val style = Style { background(Color.Blue) }

Następnie możesz przekazać zdefiniowany styl do parametru stylu kompozycji lub za pomocą Modifier.styleable. Gdy używasz Modifier.styleable, musisz też utworzyć obiekt StyleState. StyleState jest szczegółowo opisany w dokumentacji Stan i animacje ze stylami.

Poniższy przykład pokazuje, jak możesz zastosować styl bezpośrednio za pomocą wbudowanych parametrów komponentu lub za pomocą Modifier.styleable:

val style = Style { background(Color.Blue) }

// built in parameter
BaseButton(onClick = { }, style = style) {
    BaseText("Button")
}

// modifier styleable
val styleState = remember { MutableStyleState(null) }
Column(
    Modifier.styleable(styleState, style)
) {
    BaseText("Column content")
}

Możesz też przekazać ten styl do wielu komponentów:

val style = Style { background(Color.Blue) }

// built in parameter
BaseButton(onClick = { }, style = style) {
    BaseText("Button")
}
BaseText("Different text that uses the same style parameter", style = style)

// modifier styleable
val columnStyleState = remember { MutableStyleState(null) }
Column(
    Modifier.styleable(columnStyleState, style)
) {
    BaseText("Column")
}
val rowStyleState = remember { MutableStyleState(null) }
Row(
    Modifier.styleable(rowStyleState, style)
) {
    BaseText("Row")
}

Dodawanie wielu właściwości stylu

Możesz dodać wiele właściwości stylu, ustawiając różne właściwości w każdym wierszu:

BaseButton(
    onClick = { },
    style = {
        background(Color.Blue)
        contentPaddingStart(16.dp)
    }
) {
    BaseText("Button")
}

Właściwości w stylach nie są addytywne, w przeciwieństwie do stylów opartych na modyfikatorach. Style przyjmują ostatnią ustawioną wartość na liście właściwości w bloku stylu. W poniższym przykładzie tło jest ustawione 2 razy, więc zastosowane tło to TealColor. W przypadku dopełnienia contentPaddingTop zastępuje dopełnienie górne ustawione przez contentPadding i nie łączy wartości.

BaseButton(
    style = {
        background(Color.Red)
        // Background of Red is now overridden with TealColor instead
        background(TealColor)
        // All directions of padding are set to 64.dp (top, start, end, bottom)
        contentPadding(64.dp)
        // Top padding is now set to 16.dp, all other paddings remain at 64.dp
        contentPaddingTop(16.dp)
    },
    onClick = {
        //
    }
) {
    BaseText("Click me!")
}

Przycisk z ustawionymi 2 kolorami tła i 2 zastąpieniami contentPadding
Rysunek 1. Przycisk z ustawionymi 2 kolorami tła i 2 zastąpieniami contentPadding.

Scalanie wielu obiektów stylu

Możesz utworzyć wiele obiektów stylu i przekazać je do parametru stylu kompozycji.

val style1 = Style { background(TealColor) }
val style2 = Style { contentPaddingTop(16.dp) }

BaseButton(
    style = style1 then style2,
    onClick = {

    },
) {
    BaseText("Click me!")
}

Przycisk z kolorem tła i ustawionym parametrem contentPaddingTop
Rysunek 2. Przycisk z ustawionym kolorem tła i contentPaddingTop.

Jeśli kilka stylów określa tę samą właściwość, wybierana jest ostatnia ustawiona właściwość. Ponieważ właściwości w stylach nie są addytywne, ostatnie przekazane dopełnienie zastępuje contentPaddingHorizontal ustawione przez początkowe contentPadding. Dodatkowo ostatni kolor tła zastępuje kolor tła ustawiony przez początkowy przekazany styl.

val style1 = Style {
    background(Color.Red)
    contentPadding(32.dp)
}

val style2 = Style {
    contentPaddingHorizontal(8.dp)
    background(Color.LightGray)
}

BaseButton(
    style = style1 then style2,
    onClick = {

    },
) {
    BaseText("Click me!")
}

W tym przypadku zastosowany styl ma jasnoszare tło i dopełnienie 32.dp, z wyjątkiem dopełnienia z lewej i prawej strony, które ma wartość 8.dp.

Przycisk z wartością contentPadding zastąpioną przez różne style
Rysunek 3. Przycisk z contentPadding, który jest zastępowany przez różne style.

Dziedziczenie stylu

Niektóre właściwości stylu, takie jak contentColor i właściwości związane ze stylem tekstu, są przekazywane do kompozycji podrzędnych. Styl ustawiony w kompozycji podrzędnej zastępuje odziedziczony styl nadrzędny w przypadku tej konkretnej kompozycji podrzędnej.

Przekazywanie stylu za pomocą parametrów Style, styleable i direct
Rysunek 4. Przekazywanie stylu za pomocą Style, styleable i parametrów bezpośrednich.
Priorytet Metoda Efekt
1 (najwyższy) Argumenty bezpośrednie w kompozycji Zastępuje wszystko, np. Text(color = Color.Red)
2 Parametr stylu Styl lokalny zastępuje Text(style = Style { contentColor(Color.Red)}
3 Łańcuch modyfikatorów Modifier.styleable{ contentColor(Color.Red) w samym komponencie.
4 (najniższy) Style nadrzędne W przypadku właściwości, które można dziedziczyć (typografia/kolor), przekazywanych z elementu nadrzędnego.

Styl nadrzędny

Możesz ustawić właściwości tekstu (takie jak contentColor) w kompozycji nadrzędnej, a zostaną one przekazane do wszystkich kompozycji podrzędnych Text.

val styleState = remember { MutableStyleState(null) }
Column(
    modifier = Modifier.styleable(styleState) {
        background(Color.LightGray)
        val blue = Color(0xFF4285F4)
        val purple = Color(0xFFA250EA)
        val colors = listOf(blue, purple)
        contentBrush(Brush.linearGradient(colors))
    },
) {
    BaseText("Children inherit", style = { width(60.dp) })
    BaseText("certain properties")
    BaseText("from their parents")
}

Dziedziczenie właściwości komponentów podrzędnych
Rysunek 5. Dziedziczenie właściwości kompozycji podrzędnych.

Zastępowanie właściwości przez elementy podrzędne

Możesz też ustawić styl w konkretnej kompozycji Text. Jeśli kompozycja nadrzędna ma ustawiony styl, styl ustawiony w kompozycji podrzędnej zastępuje styl kompozycji nadrzędnej.

val styleState = remember { MutableStyleState(null) }
Column(
    modifier = Modifier.styleable(styleState) {
        background(Color.LightGray)
        val blue = Color(0xFF4285F4)
        val purple = Color(0xFFA250EA)
        val colors = listOf(blue, purple)
        contentBrush(Brush.linearGradient(colors))
    },
) {
    BaseText("Children can ", style = {
        contentBrush(Brush.linearGradient(listOf(Color.Red, Color.Blue)))
    })
    BaseText("override properties")
    BaseText("set by their parents")
}

Komponenty podrzędne zastępują właściwości komponentów nadrzędnych
Rysunek 6. Kompozycje podrzędne zastępują właściwości nadrzędne.

Implementowanie niestandardowych właściwości stylu

Możesz tworzyć właściwości niestandardowe, które są mapowane na istniejące definicje stylu, używając funkcji rozszerzających w StyleScope, jak pokazano w tym przykładzie:

fun StyleScope.outlinedBackground(color: Color) {
    border(1.dp, color)
    background(color)
}

Zastosuj tę nową właściwość w definicji stylu:

val customExtensionStyle = Style {
    outlinedBackground(Color.Blue)
}

Tworzenie nowych właściwości z możliwością stylizowania nie jest obsługiwane. Jeśli Twój przypadek użycia wymaga takiego wsparcia, prześlij prośbę o dodanie funkcji.

Odczytywanie wartości CompositionLocal

Często stosowanym wzorcem jest przechowywanie tokenów systemu projektowania w CompositionLocal, aby uzyskiwać dostęp do zmiennych bez konieczności przekazywania ich jako parametrów. Style mogą uzyskiwać dostęp do CompositionLocal, aby pobierać wartości w całym systemie w ramach stylu:

val buttonStyle = Style {
    contentPadding(12.dp)
    shape(RoundedCornerShape(50))
    background(Brush.verticalGradient(LocalCustomColors.currentValue.background))
}