Ta strona zawiera ogólny przegląd warstw architektury, z których składa się Jetpack Compose, oraz podstawowe zasady, na których opiera się ten projekt.
Jetpack Compose nie jest pojedynczym projektem monolitycznym – składa się z kilku modułów, które są połączone razem w całości. Zrozumienie różnych modułów, które składają się na Jetpack Compose, pozwala:
- Przy tworzeniu aplikacji lub biblioteki używaj odpowiedniego poziomu abstrakcji
- Dowiedz się, kiedy możesz „zejść” na niższy poziom, by zyskać większą kontrolę lub dostosowanie.
- Minimalizuj zależności
Warstwy
Główne warstwy gry Jetpack Compose to:
Rysunek 1. Główne warstwy Jetpack Compose.
Każda warstwa jest tworzona na niższych poziomach i łączy różne funkcje, aby tworzyć komponenty wyższej jakości. Każda warstwa korzysta z publicznych interfejsów API dolnych warstw, aby zweryfikować granice modułów i w razie potrzeby zastąpić dowolną warstwę. Przyjrzyjmy się tym warstwom od dołu do góry.
- Środowisko wykonawcze
- W tym module poznasz podstawowe informacje o środowisku wykonawczym tworzenia wiadomości, takie jak
remember
,mutableStateOf
, adnotacje@Composable
iSideEffect
. Jeśli potrzebujesz umiejętności zarządzania drzewami w komponencie, a nie interfejsu użytkownika, możesz rozważyć tworzenie go bezpośrednio na tej warstwie. - Interfejs użytkownika
- Warstwa interfejsu składa się z wielu modułów (
ui-text
,ui-graphics
,ui-tooling
itp.). Moduły te implementują podstawowe narzędzia interfejsu, takie jakLayoutNode
,Modifier
, moduły obsługi wprowadzania danych, układy niestandardowe i rysunki. Możesz skorzystać z tej warstwy, jeśli potrzebujesz tylko podstawowych koncepcji zestawu narzędzi interfejsu. - Podstawa
- Ten moduł zawiera niezależne od systemu projektowania elementy interfejsu użytkownika Compose, takie jak
Row
,Column
,LazyColumn
, rozpoznawanie konkretnych gestów itp. Możesz też stworzyć własny system projektowania oparty na warstwie podstawowej. - Materiał
- W tym module omówiono wdrożenie systemu Material Design UI w interfejsie Compose, w tym system tworzenia motywów, elementy stylu, wskaźniki fali oraz ikony. Wykorzystaj tę warstwę, korzystając z interfejsu Material Design w swojej aplikacji.
Zasady dotyczące projektowania
Główną zasadą w Jetpack Compose jest udostępnianie małych, wyspecjalizowanych elementów, które można połączyć (lub skomponować) razem, a nie jako kilka monolitycznych elementów. Takie podejście ma wiele zalet.
Sterowanie
Komponenty o wyższym poziomie zwykle działają lepiej, ale ograniczają Twoją bezpośrednią kontrolę. Jeśli potrzebujesz większej kontroli, możesz użyć komponentu niższego poziomu.
Jeśli na przykład chcesz animować kolor komponentu, możesz użyć interfejsu API animateColorAsState
:
val color = animateColorAsState(if (condition) Color.Green else Color.Red)
Jeśli jednak komponent ma zawsze mieć kolor szary, nie możesz tego zrobić za pomocą tego interfejsu API. Możesz ją rozwinąć, aby użyć interfejsu API Animatable
niższego poziomu:
val color = remember { Animatable(Color.Gray) } LaunchedEffect(condition) { color.animateTo(if (condition) Color.Green else Color.Red) }
Interfejs animateColorAsState
API wyższego poziomu jest utworzony na podstawie interfejsu Animatable
API niższego poziomu. Korzystanie z interfejsu API niższego poziomu jest bardziej złożone, ale daje większą kontrolę. Wybierz poziom abstrakcji, który najlepiej odpowiada Twoim potrzebom.
Personalizacja
Połączenie komponentów wyższego poziomu z mniejszych elementów znacznie ułatwia dostosowywanie komponentów. Spójrzmy na przykład na implementację komponentu Button
za pośrednictwem warstwy Material:
@Composable fun Button( // … content: @Composable RowScope.() -> Unit ) { Surface(/* … */) { CompositionLocalProvider(/* … */) { // set LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { Row( // … content = content ) } } } }
Button
składa się z 4 komponentów:
Materiał
Surface
, który określa tło, kształt, obsługę kliknięć itp.CompositionLocalProvider
, który zmienia wersję alfa treści po włączeniu lub wyłączeniu przycisku.ProvideTextStyle
ustawia domyślny styl tekstu, który będzie używanyRow
określa domyślne zasady układu treści przycisku.
Pominęliśmy niektóre parametry i komentarze, aby zwiększyć przejrzystość struktury, ale cały komponent składa się tylko z 40 wierszy kodu, ponieważ po prostu łączy te 4 komponenty w celu implementacji przycisku. Komponenty takie jak Button
oceniają, jakie parametry są udostępniane. Pozwala to znaleźć równowagę między umożliwianiem typowych dostosowań a eksplozją parametrów, które mogą utrudniać korzystanie z danego komponentu. Na przykład komponenty Material Design oferują możliwość dostosowania
określonego w systemie Material Design, aby ułatwić przestrzeganie zasad Material Design.
Jeśli jednak chcesz dostosować komponent poza parametrami, możesz „zpuścić” poziom i utworzyć rozwidlenie komponentu. Na przykład styl Material Design określa, że przyciski powinny mieć jednolite tło. Jeśli potrzebujesz tła w postaci gradientu, parametry Button
nie obsługują tej opcji. W takim przypadku możesz jako odniesienia użyć implementacji Material Button
i utworzyć własny komponent:
@Composable fun GradientButton( // … background: List<Color>, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background( Brush.horizontalGradient(background) ) ) { CompositionLocalProvider(/* … */) { // set material LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { content() } } } }
W powyższej implementacji nadal używa się komponentów z warstwy Material, takich jak koncepcja obecnej wersji alfa interfejsu Material Design i bieżący styl tekstu. Zastępuje jednak materiał Surface
elementem Row
i nadaje mu styl, aby uzyskać odpowiedni wygląd.
Jeśli nie chcesz używać Material Concepts, np. tworzysz własny system projektowania dostosowanego do indywidualnych potrzeb, możesz z kolei skorzystać z komponentów warstwy podstawowej:
@Composable fun BespokeButton( // … backgroundColor: Color, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background(backgroundColor) ) { // No Material components used content() } }
Jetpack Compose zastrzega najprostsze nazwy komponentów najwyższego poziomu. Na przykład androidx.compose.material.Text
opiera się na androidx.compose.foundation.text.BasicText
.
Dzięki temu możesz nadać własną implementację o największej wykrywalnej nazwie, jeśli chcesz zastąpić wyższe poziomy.
Wybieranie odpowiedniej abstrakcji
Przyjęta przez nas filozofia tworzenia warstwowych komponentów wielokrotnego użytku oznacza, że nie zawsze należy sięgać po elementy składowe niższego poziomu. Wiele komponentów wyższego poziomu nie tylko zapewnia większą funkcjonalność, ale często stosuje sprawdzone metody, takie jak obsługa ułatwień dostępu.
Jeśli na przykład chcesz dodać do komponentu niestandardowego obsługę gestów, możesz utworzyć go od podstaw, korzystając z Modifier.pointerInput
, ale istnieją inne komponenty wyższego poziomu, które mogą być dobrym punktem wyjścia, np. Modifier.draggable
, Modifier.scrollable
lub Modifier.swipeable
.
Najlepiej jest korzystać z komponentu najwyższego poziomu, który obejmuje funkcje potrzebne do korzystania z uwzględnionych sprawdzonych metod.
Więcej informacji
Aby dowiedzieć się, jak utworzyć własny system do projektowania, zapoznaj się z przykładem Jeetsnack.
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony
- Kotlin dla Jetpack Compose
- Listy i siatki
- Efekty uboczne w oknie tworzenia wiadomości