Modyfikatory umożliwiają dekorowanie lub rozszerzanie funkcji kompozycyjnych. Modyfikatory umożliwiają wykonywanie takich czynności:
- zmieniać rozmiar, układ, działanie i wygląd funkcji kompozycyjnej;
- Dodawanie informacji, np. etykiet ułatwień dostępu
- Przetwarzanie danych wejściowych użytkownika
- Dodawanie interakcji wyższego poziomu, takich jak możliwość kliknięcia, przewijania, przeciągania lub powiększania elementu.
Modyfikatory to standardowe obiekty Kotlin. Utwórz modyfikator, wywołując jedną z funkcji klasy Modifier
:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
Możesz łączyć te funkcje, aby je komponować:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
W powyższym kodzie zwróć uwagę na różne funkcje modyfikujące użyte razem.
padding
dodaje odstępy wokół elementu.fillMaxWidth
sprawia, że komponent kompozycyjny wypełnia maksymalną szerokość przekazaną mu przez element nadrzędny.
Zgodnie ze sprawdzonymi metodami wszystkie funkcje kompozycyjne powinny akceptować parametr modifier
i przekazywać go do pierwszego elementu podrzędnego, który emituje interfejs.
Dzięki temu kod jest bardziej wielokrotnego użytku, a jego działanie staje się bardziej przewidywalne i intuicyjne. Więcej informacji znajdziesz w wytycznych dotyczących interfejsu Compose API, w sekcji Elementy akceptują i respektują parametr modyfikatora.
Kolejność modyfikatorów ma znaczenie
Kolejność funkcji modyfikujących ma znaczenie. Każda funkcja wprowadza zmiany w wartości Modifier
zwróconej przez poprzednią funkcję, więc kolejność ma wpływ na wynik końcowy. Oto przykład:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
W powyższym kodzie klikalny jest cały obszar, w tym otaczający go margines wewnętrzny, ponieważ modyfikator padding
został zastosowany po modyfikatorze clickable
. Jeśli kolejność modyfikatorów zostanie odwrócona, spacja dodana przez padding
nie będzie reagować na dane wejściowe użytkownika:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
Wbudowane modyfikatory
Jetpack Compose udostępnia listę wbudowanych modyfikatorów, które pomagają dekorować lub rozszerzać funkcjonalność komponentu. Oto kilka typowych modyfikatorów, których będziesz używać do dostosowywania układów.
padding
i size
Domyślnie kompozycje w Compose otaczają swoje elementy podrzędne. Możesz jednak ustawić rozmiar za pomocą modyfikatora size
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
Pamiętaj, że określony rozmiar może nie zostać uwzględniony, jeśli nie spełnia ograniczeń pochodzących z elementu nadrzędnego układu. Jeśli chcesz, aby rozmiar elementu kompozycyjnego był stały niezależnie od ograniczeń przychodzących, użyj modyfikatora requiredSize
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
W tym przykładzie nawet jeśli element nadrzędny height
ma wartość 100.dp
, wysokość elementu Image
będzie wynosić 150.dp
, ponieważ modyfikator requiredSize
ma wyższy priorytet.
Jeśli chcesz, aby układ podrzędny wypełniał całą dostępną wysokość dozwoloną przez element nadrzędny, dodaj modyfikator fillMaxHeight
(Compose udostępnia też fillMaxSize
i fillMaxWidth
):
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
Aby dodać dopełnienie wokół elementu, ustaw modyfikator padding
.
Jeśli chcesz dodać do tekstu dopełnienie powyżej linii bazowej, aby uzyskać określoną odległość od góry układu do linii bazowej, użyj modyfikatora paddingFromBaseline
:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
Przesunięcie
Aby umieścić układ względem jego pierwotnej pozycji, dodaj modyfikator offset
i ustaw przesunięcie na osiach x i y.
Przesunięcia mogą być dodatnie lub niedodatnie. Różnica między padding
a offset
polega na tym, że dodanie offset
do komponentu nie zmienia jego wymiarów:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
Modyfikator offset
jest stosowany w poziomie zgodnie z kierunkiem układu.
W kontekście od lewej do prawej dodatnia wartość offset
przesuwa element w prawo, a w kontekście od prawej do lewej przesuwa go w lewo.
Jeśli chcesz ustawić przesunięcie bez uwzględniania kierunku układu, zapoznaj się z modyfikatorem
absoluteOffset
, w którym dodatnia wartość przesunięcia zawsze przesuwa element w prawo.
Modyfikator offset
udostępnia 2 przeciążenia: offset
, które przyjmuje przesunięcia jako parametry, i offset
, które przyjmuje wyrażenie lambda.
Więcej informacji o tym, kiedy używać poszczególnych funkcji i jak optymalizować skuteczność, znajdziesz w sekcji Skuteczność kompozycji – odraczaj odczyty tak długo, jak to możliwe.
Bezpieczeństwo zakresu w Compose
W Compose są modyfikatory, których można używać tylko w przypadku elementów podrzędnych określonych komponentów. Compose wymusza to za pomocą zakresów niestandardowych.
Jeśli na przykład chcesz, aby element podrzędny był tak duży jak element nadrzędny Box
bez wpływu na Box
rozmiar, użyj modyfikatora
matchParentSize
. matchParentSize
jest dostępna tylko w BoxScope
.
Dlatego można go używać tylko w przypadku dziecka w grupie rodzinnej Box
.
Bezpieczeństwo zakresu zapobiega dodawaniu modyfikatorów, które nie działają w innych funkcjach kompozycyjnych i zakresach, co pozwala zaoszczędzić czas na próby i błędy.
Modyfikatory z zakresem informują rodzica o pewnych kwestiach, które powinien wiedzieć o dziecku. Są one też często nazywane modyfikatorami danych nadrzędnych. Ich wewnętrzna struktura różni się od modyfikatorów ogólnego przeznaczenia, ale z perspektywy użytkowania te różnice nie mają znaczenia.
matchParentSize
w: Box
Jak wspomnieliśmy powyżej, jeśli chcesz, aby układ podrzędny miał taki sam rozmiar jak układ nadrzędny, ale nie wpływał na rozmiar układu nadrzędnego, użyj modyfikatora matchParentSize
.Box
Box
Pamiętaj, że matchParentSize
jest dostępny tylko w zakresie Box
, co oznacza, że ma zastosowanie tylko do bezpośrednich elementów podrzędnych funkcji kompozycyjnych Box
.
W przykładzie poniżej element podrzędny Spacer
przejmuje rozmiar od elementu nadrzędnego Box
, który z kolei przejmuje rozmiar od największych elementów podrzędnych, w tym przypadku ArtistCard
.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
Gdyby zamiast matchParentSize
użyto fillMaxSize
, element Spacer
zająłby całą dostępną przestrzeń dozwoloną dla elementu nadrzędnego, co spowodowałoby rozszerzenie elementu nadrzędnego i wypełnienie całej dostępnej przestrzeni.
weight
w Row
i Column
Jak widać w poprzedniej sekcji dotyczącej wypełnienia i rozmiaru, domyślnie rozmiar komponentu jest określany przez zawartość, którą otacza. Rozmiar funkcji kompozycyjnej możesz ustawić tak, aby był elastyczny w ramach elementu nadrzędnego, używając weight
modyfikatora dostępnego tylko w RowScope
i ColumnScope
.
Weźmy Row
, który zawiera 2 funkcje kompozycyjne Box
.
Pierwsze pole ma 2 razy większą wartość weight
niż drugie, więc ma 2 razy większą szerokość. Ponieważ Row
ma szerokość 210.dp
, pierwsza Box
ma szerokość 140.dp
, a druga 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
Wyodrębnianie i ponowne wykorzystywanie modyfikatorów
Można połączyć ze sobą kilka modyfikatorów, aby udekorować lub rozszerzyć element kompozycyjny. Łańcuch jest tworzony za pomocą interfejsu Modifier
, który reprezentuje uporządkowaną, niezmienną listę pojedynczych Modifier.Elements
.
Każdy symbol Modifier.Element
reprezentuje indywidualne zachowanie, np. zachowania związane z układem, rysowaniem i grafiką, wszystkie zachowania związane z gestami, zachowania związane z ogniskiem i semantyką, a także zdarzenia wejścia na urządzeniu. Kolejność ma znaczenie: elementy modyfikujące dodane jako pierwsze zostaną zastosowane jako pierwsze.
Czasami warto ponownie używać tych samych instancji łańcucha modyfikatorów w wielu funkcjach kompozycyjnych, wyodrębniając je do zmiennych i przenosząc do zakresów wyższego poziomu. Może to poprawić czytelność kodu lub wydajność aplikacji z kilku powodów:
- Ponowne przypisanie modyfikatorów nie będzie powtarzane, gdy nastąpi ponowna kompozycja w przypadku funkcji kompozycyjnych, które ich używają.
- Łańcuchy modyfikatorów mogą być bardzo długie i złożone, więc ponowne użycie tej samej instancji łańcucha może zmniejszyć obciążenie środowiska wykonawczego Compose podczas porównywania ich.
- Wyodrębnianie kodu zwiększa jego przejrzystość, spójność i łatwość utrzymania w całej bazie kodu.
Sprawdzone metody ponownego wykorzystywania modyfikatorów
Twórz własne Modifier
i wyodrębniaj je, aby używać ich w wielu komponentach kompozycyjnych. Możesz po prostu zapisać modyfikator, ponieważ jest on obiektem podobnym do danych:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Wyodrębnianie i ponowne wykorzystywanie modyfikatorów podczas obserwowania często zmieniającego się stanu
Obserwowanie często zmieniających się stanów w funkcjach kompozycyjnych, takich jak stany animacji lub scrollState
, może powodować znaczną liczbę ponownych kompozycji. W takim przypadku modyfikatory będą przypisywane przy każdej rekompozycji i potencjalnie przy każdej klatce:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
Zamiast tego możesz utworzyć, wyodrębnić i ponownie użyć tę samą instancję modyfikatora i przekazać ją do funkcji kompozycyjnej w ten sposób:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
Wyodrębnianie i ponowne wykorzystywanie modyfikatorów bez zakresu
Modyfikatory mogą być nieograniczone lub ograniczone do konkretnego komponentu. W przypadku modyfikatorów bez zakresu możesz je łatwo wyodrębnić poza funkcje kompozycyjne jako proste zmienne:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Może to być szczególnie korzystne w połączeniu z układami leniwymi. W większości przypadków chcesz, aby wszystkie Twoje produkty, których może być znaczna liczba, miały dokładnie te same modyfikatory:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
Wyodrębnianie i ponowne wykorzystywanie modyfikatorów o określonym zakresie
W przypadku modyfikatorów, które są ograniczone do określonych funkcji kompozycyjnych, możesz wyodrębnić je na najwyższy możliwy poziom i ponownie wykorzystać w odpowiednich miejscach:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
Wyodrębnione modyfikatory o określonym zakresie należy przekazywać tylko do bezpośrednich elementów podrzędnych o tym samym zakresie. Więcej informacji o tym, dlaczego jest to ważne, znajdziesz w sekcji Bezpieczeństwo zakresu w Compose:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
Dalsze łączenie wyodrębnionych modyfikatorów
Możesz połączyć lub dołączyć wyodrębnione ciągi modyfikatorów, wywołując funkcję
.then()
:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
Pamiętaj, że kolejność modyfikatorów ma znaczenie.
Więcej informacji
Udostępniamy pełną listę modyfikatorów wraz z ich parametrami i zakresami.
Więcej informacji o używaniu modyfikatorów znajdziesz w ćwiczeniu z programowania dotyczącym podstawowych układów w Compose lub w repozytorium Now in Android.
Więcej informacji o modyfikatorach niestandardowych i sposobie ich tworzenia znajdziesz w dokumentacji Układy niestandardowe – używanie modyfikatora układu.
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony.
- Podstawy układu tworzenia
- Działania edytora {:#editor-actions}
- Układy niestandardowe {:#custom-layouts }