Jetpack Compose znacznie ułatwia projektowanie i tworzenie interfejsu użytkownika aplikacji. Compose przekształca stan w elementy interfejsu za pomocą:
- Kompozycja elementów
- Układ elementów
- Rysowanie elementów
Ten dokument skupia się na układzie elementów i objaśnia niektóre elementy składowe dostępne w usłudze Compose, aby pomóc Ci rozmieścić elementy interfejsu.
Cele układów w polu tworzenia wiadomości
Implementacja systemu układu w Jetpack Compose ma 2 główne cele:
- Wysoka wydajność
- możliwość łatwego tworzenia niestandardowych układów.
Podstawowe informacje o funkcjach kompozycyjnych
Funkcje składane to podstawowy element Compose. Funkcja kompozycyjna to funkcja wysyłająca obiekt Unit
, który opisuje część interfejsu użytkownika. Funkcja ta przyjmuje dane wejściowe i generuje to, co jest widoczne na ekranie. Więcej informacji o komponowalnych znajdziesz w dokumentacji dotyczącej modelu mentalnego kompozytowania.
Funkcja kompozycyjna może generować kilka elementów interfejsu. Jeśli jednak nie doradzisz, jak je rozmieścić, funkcja Utwórz może uporządkować elementy w sposób, który Ci nie odpowiada. Ten kod generuje na przykład 2 elementy tekstowe:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
Bez wskazówek dotyczących układu elementów tekstowych Compose układa je jeden na drugim, przez co stają się one nieczytelne:
Compose zawiera kolekcję gotowych do użycia układów, które pomagają rozmieszczać elementy interfejsu i ułatwiają definiowanie własnych, bardziej specjalistycznych układów.
Komponenty standardowego układu
W wielu przypadkach możesz po prostu użyć standardowych elementów układu w Compose.
Użyj Column
, aby umieścić elementy pionowo na ekranie.
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
Podobnie, aby umieścić elementy poziomo na ekranie, użyj Row
. Zarówno element Column
, jak i element Row
umożliwiają konfigurowanie wyrównania elementów, które zawierają.
@Composable fun ArtistCardRow(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
Użyj narzędzia Box
, aby umieścić elementy na innym. Box
obsługuje też konfigurowanie dokładnego wyrównania elementów.
@Composable fun ArtistAvatar(artist: Artist) { Box { Image(bitmap = artist.image, contentDescription = "Artist image") Icon(Icons.Filled.Check, contentDescription = "Check mark") } }
Często te elementy są wszystkim, czego potrzebujesz. Możesz napisać własną funkcję kompozycyjną, aby połączyć te układy w bardziej skomplikowany układ pasujący do Twojej aplikacji.
Aby ustawić pozycję elementu podrzędnego w elemencie Row
, ustaw argumenty horizontalArrangement
i verticalAlignment
. W przypadku Column
ustaw argumenty verticalArrangement
i horizontalAlignment
:
@Composable fun ArtistCardArrangement(artist: Artist) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { /*...*/ } } }
Model układu
W modelu układu drzewo interfejsu jest układane w jednym przejeździe. Każdy węzeł jest najpierw proszony o zmierzenie siebie, a potem rekurencyjnie o zmierzenie wszystkich podrzędnych węzłów, przekazując ograniczenia rozmiaru w drzewie do podrzędnych węzłów. Następnie określa się rozmiary i miejsce umieszczenia węzłów liści, a rozwiązane rozmiary i instrukcje dotyczące umieszczenia są przekazywane z powrotem do drzewa.
Krótko mówiąc, rodzice mierzą się przed dziećmi, ale ich rozmiar i pozycja są określane po ich dzieciach.
Rozważ funkcję SearchResult
.
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
Ta funkcja zwraca to drzewo interfejsu użytkownika.
SearchResult
Row
Image
Column
Text
Text
W przykładzie SearchResult
układ drzewa interfejsu użytkownika jest następujący:
- Wskaźnik jest żądany dla węzła głównego
Row
. - Węzeł główny
Row
prosi pierwszy element podrzędny,Image
, o zmierzenie. Image
to węzeł liścia (czyli nie ma żadnych elementów podrzędnych), więc podaje rozmiar i zwraca instrukcje dotyczące umieszczenia.- Węzeł główny
Row
prosi swoje drugie dziecko,Column
, o zmierzenie. - Węzeł
Column
prosi pierwszy element podrzędnyText
o zmierzenie. - Pierwszy węzeł
Text
jest węzłem-liściem, więc podaje rozmiar i zwraca instrukcje dotyczące umieszczenia. - Węzeł
Column
prosi swoje drugie dzieckoText
o pomiar. - Drugi węzeł
Text
jest węzłem liścia, więc zgłasza rozmiar i zwraca instrukcje miejsca docelowego. - Teraz, gdy węzeł
Column
zmierzył i umieścił swoje elementy podrzędne, może określić swój rozmiar i położenie. - Teraz, gdy węzeł główny
Row
zmierzył i umieścił swoje elementy potomne, może określić swój rozmiar i położenie.
Wydajność
Tworzenie wiadomości osiąga wysoką skuteczność dzięki mierzeniu aktywności dzieci tylko raz. Pomiar w pojedynczym przejściu pozytywnie wpływa na wydajność, ponieważ pozwala Compose sprawnie obsługiwać głębokie drzewa interfejsu użytkownika. Jeśli element zmierzy swój element potomny 2 razy, a ten zmierzy swoje potomne elementy 2 razy i tak dalej, jedno ułożenie całego interfejsu będzie wymagało dużo pracy, co utrudni utrzymanie wydajności aplikacji.
Jeśli układ wymaga z jakiegoś powodu kilku pomiarów, Compose oferuje specjalny system pomiarów wewnętrznych. Więcej informacji o tej funkcji znajdziesz w artykule Własne pomiary w układance w Compose.
Ponieważ pomiar i rozmieszczenie to odrębne etapy przepływu danych, wszelkie zmiany, które wpływają tylko na umieszczanie elementów, a nie na pomiar, mogą być wykonywane osobno.
Używanie modyfikatorów w układach
Jak wspomnieliśmy w artykule Modyfikatory tworzenia wiadomości, możesz ich używać do dekorowania lub rozszerzania swoich elementów kompozycyjnych. Modyfikatory są niezbędne do dostosowywania układu. Na przykład tutaj łańcuchujemy kilka modyfikatorów, aby dostosować ArtistCard
:
@Composable fun ArtistCardModifiers( artist: Artist, onClick: () -> Unit ) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ } Spacer(Modifier.size(padding)) Card( elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), ) { /*...*/ } } }
W powyższym kodzie zwróć uwagę na różne funkcje modyfikujące używane razem.
clickable
sprawia, że komponent reaguje na działania użytkownika i wyświetla efekt falowania.padding
umieszcza odstęp wokół elementu.fillMaxWidth
powoduje, że kompozyt wypełnia maksymalną szerokość określoną przez jego nadrzędny element.size()
określa preferowaną szerokość i wysokość elementu.
układy przewijalne,
Więcej informacji o przewijanych układach znajdziesz w dokumentacji gestów w komponowaniu wiadomości.
Więcej informacji o listach i listach leniwych znajdziesz w dokumentacji dotyczącej tworzenia list.
Układy elastyczne
Przy projektowaniu układu należy brać pod uwagę różne orientacje ekranu i rozmiary formatów. Compose oferuje kilka wbudowanych mechanizmów, które ułatwiają dostosowanie układów do różnych konfiguracji ekranu.
Ograniczenia
Aby poznać ograniczenia pochodzące z elementu nadrzędnego i odpowiednio zaprojektować układ, możesz użyć BoxWithConstraints
. Ograniczenia pomiarów można znaleźć w zakresie lambda treści. Za pomocą tych ograniczeń pomiarowych możesz tworzyć różne układy dla różnych konfiguracji ekranu:
@Composable fun WithConstraintsComposable() { BoxWithConstraints { Text("My minHeight is $minHeight while my maxWidth is $maxWidth") } }
Układy oparte na slotach
Compose udostępnia wiele komponentów opartych na Material Design z zależnością androidx.compose.material:material
(dostępną podczas tworzenia projektu Compose w Android Studio), aby ułatwić tworzenie interfejsu użytkownika. Dostępne są elementy Drawer
, FloatingActionButton
i TopAppBar
.
Komponenty Material Design intensywnie korzystają z interfejsów API slotów, czyli wzoru, który wdrożono w Compose, aby umożliwić dostosowanie komponentów składanych. Dzięki temu komponenty są bardziej elastyczne, ponieważ mogą przyjmować element podrzędny, który może konfigurować się samodzielnie, zamiast udostępniać wszystkie parametry konfiguracji elementu podrzędnego.
Przedziały pozostawiają w interfejsie puste miejsce, w którym deweloper może wypełniać je według własnego uznania. Na przykład w usługach TopAppBar
możesz dostosować te sloty:
Elementy składane zwykle korzystają z komponowalnego interfejsu lambda content
( content: @Composable
() -> Unit
). Interfejsy API slotów udostępniają wiele parametrów content
do określonych zastosowań.
Na przykład TopAppBar
umożliwia Ci udostępnianie treści w przypadku title
,
navigationIcon
i actions
.
Na przykład:
Scaffold
pozwala na implementację interfejsu z podstawową strukturą układu Material Design.
Scaffold
zawiera sloty na najpopularniejsze komponenty Material na najwyższym poziomie, takie jak TopAppBar
,
BottomAppBar
,
FloatingActionButton
i Drawer
. Dzięki użyciu Scaffold
możesz łatwo sprawdzić, czy te komponenty są prawidłowo umieszczone i czy współpracują ze sobą.
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
Polecane dla Ciebie
- Uwaga: tekst linku wyświetla się, gdy JavaScript jest wyłączony
- Tworzenie modyfikatorów
- Kotlin w Jetpack Compose
- Komponenty i układy Material Design