Modyfikatory umożliwiają dekorowanie lub uzupełnienie elementu kompozycyjnego. Dzięki modyfikatorom możesz:
- Zmienianie rozmiaru, układu, działania i wyglądu elementu kompozycyjnego
- dodawać informacje, np. etykiety ułatwień dostępu;
- Przetwarzaj dane wejściowe użytkownika
- Dodawaj interakcje wysokiego poziomu, np. umożliwiać klikanie, przewijanie, przeciąganie czy powiększanie.
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 połączyć te funkcje w łańcuch, aby je utworzyć:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
W kodzie powyżej zwróć uwagę na różne funkcje modyfikatorów stosowane razem.
padding
umieszcza odstęp wokół elementu.fillMaxWidth
sprawia, że funkcja kompozycyjna wypełnia maksymalną szerokość, którą otrzymuje od elementu nadrzędnego.
Sprawdzoną metodą jest, by wszystkie obiekty kompozycyjne akceptują parametr modifier
i przekazywać go do pierwszego elementu podrzędnego, który generuje interfejs użytkownika.
Dzięki temu kod jest łatwiejszy do wielokrotnego użytku, a jego działanie jest bardziej przewidywalne i intuicyjne. Więcej informacji znajdziesz w wytycznych dotyczących interfejsu Compose API w artykule Elementy akceptują i respektują parametr modyfikatora.
Kolejność modyfikatorów ma znaczenie
Kolejność funkcji modyfikatorów jest istotna. Każda funkcja wprowadza zmiany w wartości Modifier
zwróconej przez poprzednią funkcję, więc sekwencja wpływa na wynik końcowy. Spójrzmy na przykład:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
W kodzie powyżej całego obszaru można kliknąć cały obszar, w tym otaczające go dopełnienie, ponieważ modyfikator padding
został zastosowany po modyfikatorze clickable
. Jeśli kolejność modyfikatorów jest odwrócona, spacja dodana przez padding
nie reaguje 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 zawiera listę wbudowanych modyfikatorów, które pomogą Ci udekorować lub wzbogacić funkcję kompozycyjną. Oto kilka typowych modyfikatorów, których możesz używać do dostosowywania układów.
padding
i size
Domyślnie układy dostępne w sekcji Utwórz zawierają elementy podrzędne. Rozmiar możesz jednak określić, korzystając z modyfikatora size
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
Pamiętaj, że podany rozmiar może nie być respektowany, jeśli nie spełnia ograniczeń nałożonych na element nadrzędny układu. Jeśli chcesz, aby rozmiar kompozycyjny był stały bez względu na przychodzące ograniczenia, 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
wyniesie 150.dp
, ponieważ pierwszeństwo ma modyfikator requiredSize
.
Jeśli chcesz, by układ podrzędny wypełniał całą dostępną wysokość dozwoloną przez element nadrzędny, dodaj modyfikator fillMaxHeight
(do wyboru są też właściwości 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 dookoła elementu, ustaw modyfikator padding
.
Jeśli chcesz dodać dopełnienie powyżej linii bazowej tekstu, aby osiągnąć określoną odległość od górnej krawędzi układu do punktu odniesienia, 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 określić położenie układu względem jego pierwotnej pozycji, dodaj modyfikator offset
i ustaw przesunięcie na osi x i y.
Kompensacja może być dodatnia lub niedodatnia. Różnica między funkcją padding
a offset
polega na tym, że dodanie elementu offset
do funkcji kompozycyjnej nie zmienia jej pomiaró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 poziomo zgodnie z kierunkiem układu.
W kontekście od lewej do prawej dodatni offset
przesuwa element w prawo, a w kontekście od prawej do lewej – w lewo.
Jeśli musisz 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 pobiera lambda.
Szczegółowe informacje o tym, kiedy używać każdego z nich i jak zoptymalizować wydajność, znajdziesz w sekcji Wydajność tworzenia wiadomości – odkładaj czytanie jak najdłużej.
Zakres bezpieczeństwa w oknie tworzenia wiadomości
W interfejsie Compose znajdują się modyfikatory, których można używać tylko w przypadku elementów podrzędnych określonych elementów kompozycyjnych. Funkcja tworzenia wymusza to za pomocą zakresów niestandardowych.
Jeśli na przykład chcesz, aby obiekt podrzędny był większy niż nadrzędny Box
, ale nie chcesz zmieniać rozmiaru Box
, użyj modyfikatora matchParentSize
. Usługa matchParentSize
jest dostępna tylko w BoxScope
.
Dlatego można go używać tylko w przypadku konta podrzędnego należącego do rodzica w Box
.
Bezpieczeństwo zakresu uniemożliwia dodawanie modyfikatorów, które nie działają w innych funkcjach kompozycyjnych i zakresach, a także pozwala zaoszczędzić czas na metody prób i błędów.
Modyfikatory o określonym zakresie powiadamiają wydawcę nadrzędnego o pewnych informacjach o elemencie podrzędnym, które powinien mieć. Nazywa się je też nadrzędnymi modyfikatorami danych. Ich elementy wewnętrzne różnią się od zwykłych modyfikatorów, ale z perspektywy użytkowania różnice te nie mają znaczenia.
matchParentSize
w: Box
Jak już wspomnieliśmy, jeśli chcesz, by układ podrzędny miał taki sam rozmiar jak nadrzędny Box
, ale nie wpływał na rozmiar Box
, użyj modyfikatora matchParentSize
.
Pamiętaj, że właściwość matchParentSize
jest dostępna tylko w zakresie Box
, co oznacza, że ma zastosowanie tylko do bezpośrednich elementów podrzędnych funkcji kompozycyjnych Box
.
W poniższym przykładzie element podrzędny Spacer
pobiera swój rozmiar z elementu nadrzędnego (Box
), który z kolei pobiera swój 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 elementu fillMaxSize
, Spacer
zajęłoby całe dostępne miejsce dostępne dla jednostki nadrzędnej, a tym samym spowodowałoby jej rozwinięcie i wypełnienie całej dostępnej przestrzeni.
weight
w: Row
i Column
Jak wiesz już w poprzedniej sekcji dotyczącej Dopełniania i rozmiaru, domyślnie rozmiar kompozycyjny jest definiowany przez zawijanie treści. Rozmiar elementu kompozycyjnego można ustawić tak, aby był elastyczny w obrębie jego nadrzędnego, modyfikatorowi weight
, który jest dostępny tylko w interfejsach RowScope
i ColumnScope
.
Weźmy przykład Row
, który zawiera 2 kompozycje Box
.
Pierwsze pole jest 2 razy większe niż weight
drugiego, więc ma 2 razy większą szerokość. Row
ma szerokość 210.dp
, więc pierwszy wymiar (Box
) ma 140.dp
, a drugi – 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
Różne modyfikatory można łączyć, aby dekorować lub wzbogacać kompozycję. Ten łańcuch jest tworzony za pomocą interfejsu Modifier
, który reprezentuje uporządkowaną, stałą listę pojedynczych elementów Modifier.Elements
.
Każdy element Modifier.Element
reprezentuje konkretne zachowanie, takie jak działanie układu, rysowania i grafiki, wszystkie zachowania związane z gestami, skupieniem i semantyką, a także zdarzenia wejściowe urządzenia. Ich kolejność ma znaczenie: elementy modyfikujące,
które zostały dodane jako pierwsze, będą stosowane jako pierwsze.
Czasami warto używać tych samych instancji łańcucha modyfikatora w wielu elementach kompozycyjnych przez wyodrębnienie ich do zmiennych i przeniesienie ich na wyższe zakresy. Może zwiększyć czytelność kodu lub poprawić wydajność aplikacji z kilku powodów:
- Zmiana przydziału modyfikatorów nie będzie powtarzana po wykonaniu tej zmiany w elementach kompozycyjnych, które ich używają
- Łańcuchy modyfikatorów mogą być potencjalnie bardzo długie i złożone, dlatego ponowne użycie tego samego wystąpienia łańcucha może złagodzić potrzeby środowiska wykonawczego tworzenia zadań przy ich porównywaniu.
- To wyodrębnianie promuje czystość, spójność i utrzymanie kodu w bazie kodu
Sprawdzone metody ponownego wykorzystywania modyfikatorów
Utwórz własne łańcuchy typu Modifier
i wyodrębnij je, aby wykorzystać je w wielu komponentach kompozycyjnych. Nie ma potrzeby zapisywania modyfikatora, ponieważ
są to obiekty podobne do danych:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Wyodrębnianie i ponowne wykorzystywanie modyfikatorów podczas obserwacji często zmieniających się stanów
Podczas obserwacji często zmieniających się stanów w komponentach kompozycyjnych, takich jak stany animacji czy scrollState
, może dojść do sporo zmian. W takim przypadku modyfikatory zostaną przydzielone przy każdej zmianie kompozycji i potencjalnie w 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 wykorzystać to samo wystąpienie modyfikatora oraz przekazać je 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 elementu kompozycyjnego. W przypadku modyfikatorów o nieograniczonym zakresie można je łatwo wyodrębnić poza obiektami kompozycyjnymi jako proste zmienne:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Jest to szczególnie przydatne w połączeniu z leniwymi układami. W większości przypadków wszystkie potencjalnie istotne elementy mają mieć dokładnie takie 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 zakresu
Gdy zajmujesz się modyfikatorami, które są ograniczone do określonych elementów kompozycyjnych, możesz wyodrębnić je na najwyższym możliwym poziomie i ponownie je wykorzystać w razie potrzeby:
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 // ... ) // ... }
Modyfikatory wyodrębnione z zakresu należy przekazywać do elementów podrzędnych o tym samym zakresie i zakresie. Więcej informacji o tym, dlaczego jest to tak ważne, znajdziesz w sekcji Bezpieczeństwo w oknie tworzenia:
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 łańcuch wyodrębnionych modyfikatorów
Aby dodać łańcuch lub dołączyć wyodrębnione łańcuchy modyfikatorów, wywołaj 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 tylko, że kolejność modyfikatorów ma znaczenie.
Więcej informacji
Podajemy pełną listę modyfikatorów z ich parametrami i zakresami.
Aby dowiedzieć się więcej o korzystaniu z modyfikatorów, możesz też zapoznać się z podstawowymi układami w ćwiczeniach z programowania w narzędziu do tworzenia lub zapoznać się z repozytorium Now w Androidzie.
Więcej informacji o modyfikatorach niestandardowych i sposobie ich tworzenia znajdziesz w dokumentacji w artykule Układy niestandardowe – korzystanie z modyfikatora układu.
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony
- Podstawowe informacje o układzie wiadomości
- Działania edytora {:#editor-actions}
- Układy niestandardowe {:#custom-layouts }