Modyfikatory umożliwiają dekorowanie lub rozszerzanie funkcji kompozycyjnej. Modyfikatory umożliwiają:
- zmieniać rozmiar, układ, zachowanie i wygląd elementu kompozycyjnego;
- dodawać informacje, takie jak etykiety ułatwień dostępu;
- Przetwarzanie danych wejściowych użytkownika
- dodawać interakcje wysokiego poziomu, takie 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 połączyć te funkcje, aby je skomponować:
@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 modyfikatora używane razem.
paddingdodaje odstęp wokół elementu.fillMaxWidthsprawia, że element kompozycyjny wypełnia maksymalną szerokość nadaną mu przez element nadrzędny.
Sprawdzoną metodą jest, aby wszystkie funkcje kompozycyjne akceptowały parametr modifier i przekazywały ten modyfikator do pierwszego elementu podrzędnego, który emituje interfejs.
Dzięki temu kod będzie bardziej uniwersalny, a jego działanie – bardziej przewidywalne i intuicyjne. Więcej informacji znajdziesz w wytycznych dotyczących interfejsu Compose API, Elementy akceptują i respektują parametr Modifier.
Kolejność modyfikatorów ma znaczenie
Kolejność funkcji modyfikatora jest istotna. Każda funkcja wprowadza zmiany w Modifier zwróconym przez poprzednią funkcję, więc kolejność wpływa na ostateczny wynik. 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 cały obszar jest klikalny, w tym otaczające go dopełnienie, ponieważ modyfikator padding został zastosowany po modyfikatorze clickable. Jeśli kolejność modyfikatorów zostanie odwrócona, miejsce dodane 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ć funkcje kompozycyjne. Oto kilka typowych modyfikatorów, których będziesz używać do dostosowywania układów.
padding i size
Domyślnie układy udostępniane w Compose zawijają 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 przez Ciebie rozmiar może nie zostać uwzględniony, jeśli nie spełnia ograniczeń wynikających z elementu nadrzędnego układu. Jeśli chcesz, aby rozmiar funkcji kompozycyjnej 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 ustawioną wartość 100.dp, wysokość elementu Image będzie wynosić 150.dp, ponieważ modyfikator requiredSize ma pierwszeństwo.
Jeśli chcesz, aby układ podrzędny wypełniał całą dostępną wysokość dozwoloną przez układ 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.
Parametry start i end elementu padding są zgodne z kierunkiem układu. Aby dodać dopełnienie do lewej lub prawej krawędzi niezależnie od kierunku układu, użyj absolutePadding z parametrami left i right.
Jeśli chcesz dodać dopełnienie nad linią bazową tekstu, 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 ustawić 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 funkcji kompozycyjnej nie zmienia jej 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 – 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óry przyjmuje przesunięcia jako parametry, oraz offset, który przyjmuje wyrażenie lambda.
Więcej informacji o tym, kiedy używać poszczególnych opcji i jak optymalizować wydajność, znajdziesz w sekcji Wydajność Compose – 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 wtedy, gdy są stosowane do elementów podrzędnych określonych funkcji kompozycyjnych. Compose wymusza to za pomocą zakresów niestandardowych.
Jeśli na przykład chcesz, aby element podrzędny Box był tak duży jak element nadrzędny, bez wpływu na rozmiar Box, użyj modyfikatora matchParentSize. Funkcja matchParentSize jest dostępna tylko w: BoxScope.
Dlatego można go używać tylko w przypadku elementu podrzędnego w elemencie nadrzędnym Box.
Bezpieczeństwo zakresu zapobiega dodawaniu modyfikatorów, które nie działałyby w innych funkcjach kompozycyjnych i zakresach, i oszczędza czas, który trzeba by poświęcić na próby i błędy.
Modyfikatory zakresu powiadamiają element nadrzędny o informacjach, które powinien znać o elemencie podrzędnym. Są one też często nazywane modyfikatorami danych nadrzędnych. Ich wewnętrzne działanie 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 Box bez wpływu na rozmiar Box, użyj modyfikatora matchParentSize.
Pamiętaj, że matchParentSize jest dostępny tylko w zakresie Box, co oznacza, że dotyczy tylko bezpośrednich elementów podrzędnych funkcji kompozycyjnych Box.
W przykładzie poniżej element podrzędny Spacer przyjmuje rozmiar elementu nadrzędnego Box, który z kolei przyjmuje rozmiar największego elementu podrzędnego, czyli w tym przypadku ArtistCard.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
Jeśli zamiast matchParentSize użyto by fillMaxSize, Spacer zajmowałby całą dostępną przestrzeń dozwoloną dla elementu nadrzędnego, co z kolei spowodowałoby, że element nadrzędny rozszerzyłby się i wypełnił całą dostępną przestrzeń.
weight w usługach Row i Column
Jak pokazaliśmy w poprzedniej sekcji dotyczącej dopełnienia i rozmiaru, domyślnie rozmiar funkcji kompozycyjnej jest określany przez zawartość, którą ona otacza. Możesz ustawić elastyczny rozmiar elementu kompozycyjnego w elemencie nadrzędnym, używając modyfikatora weight, który jest dostępny tylko w RowScope i ColumnScope.
Weźmy element Row, który zawiera 2 komponenty Box.
Pierwsze pole ma 2 razy większą wartość weight niż drugie, więc jest 2 razy szersze. Ponieważ Row ma szerokość 210.dp, pierwszy Box ma szerokość 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 używanie modyfikatorów
Można połączyć ze sobą wiele modyfikatorów, aby udekorować lub rozszerzyć funkcję kompozycyjną. Ten łańcuch jest tworzony za pomocą interfejsu Modifier, który reprezentuje uporządkowaną, niezmienną listę pojedynczych Modifier.Elements.
Każdy element Modifier.Element reprezentuje pojedyncze zachowanie, takie jak układ, rysowanie i grafika, wszystkie zachowania związane z gestami, zaznaczeniem i semantyką, a także zdarzenia wejściowe urządzenia. Kolejność ma znaczenie: elementy modyfikatora, które zostaną dodane jako pierwsze, zostaną zastosowane jako pierwsze.
Czasami warto ponownie użyć tych samych instancji łańcucha modyfikatorów w wielu elementach kompozycyjnych, wyodrębniając je do zmiennych i przenosząc do wyższych zakresów. Może to poprawić czytelność kodu lub wydajność aplikacji z kilku powodów:
- Ponowne przydzielanie modyfikatorów nie będzie powtarzane, gdy nastąpi rekompozycja funkcji kompozycyjnych, które ich używają.
- Łańcuchy modyfikatorów mogą być bardzo długie i skomplikowane, więc ponowne użycie tej samej instancji łańcucha może zmniejszyć obciążenie środowiska wykonawczego Compose podczas ich porównywania.
- Takie wyodrębnienie sprzyja czystości, spójności i łatwości utrzymania kodu w całej bazie kodu.
Sprawdzone metody ponownego używania modyfikatorów
Twórz własne łańcuchy Modifier i wyodrębniaj je, aby używać ich w wielu komponentach kompozycyjnych. Możesz po prostu zapisać modyfikator, ponieważ są to obiekty podobne do danych:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Wyodrębnianie i ponowne używanie modyfikatorów podczas obserwowania często zmieniającego się stanu
Podczas obserwowania często zmieniających się stanów w komponentach, takich jak stany animacji lub scrollState, może wystąpić znaczna liczba rekompozycji. W takim przypadku modyfikatory będą przydzielane przy każdej rekompozycji i potencjalnie dla każdej klatki:
@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ć tej samej instancji 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 używanie modyfikatorów bez zakresu
Modyfikatory mogą być nieograniczone lub ograniczone do konkretnego elementu kompozycyjnego. 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 przydatne w połączeniu z układami Lazy. W większości przypadków chcesz, aby wszystkie Twoje produkty (których może być bardzo dużo) miały 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 używanie modyfikatorów o ograniczonym zakresie
Jeśli masz do czynienia z modyfikatorami, które są ograniczone do określonych funkcji kompozycyjnych, możesz je wyodrębnić na najwyższy możliwy poziom i używać ich ponownie tam, gdzie jest to odpowiednie:
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 dalej łączyć lub dołączać wyodrębnione łańcuchy 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.
Aby dowiedzieć się więcej o korzystaniu z modyfikatorów, możesz też zapoznać się z ćwiczeniem z programowania Podstawowe układy w Compose lub repozytorium Now in Android.
Więcej informacji o modyfikatorach niestandardowych i ich tworzeniu znajdziesz w dokumentacji dotyczącej niestandardowych układów i używania modyfikatora układu.
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Podstawowe informacje o układzie Compose
- Działania edytora {:#editor-actions}
- Układy niestandardowe {:#custom-layouts }