Lekcja 1. Funkcje kompozycyjne
Jetpack Compose opiera się na funkcjach kompozycyjnych. Funkcje te pozwalają zdefiniować
interfejs aplikacji, opisując, jak powinien wyglądać,
i podając zależności danych.
zamiast skupić się na procesie tworzenia interfejsu (inicjowanie elementu,
do rodziców itd.). Aby utworzyć funkcję kompozycyjną, po prostu dodaj
Adnotacja @Composable
do nazwy funkcji.
Dodaj element tekstowy
Aby rozpocząć, pobierz najnowszą wersję aplikacji Android Studio i utwórz aplikację, wybierając New Project (Nowy projekt) Telefon i tablet, wybierz Pusta aktywność. Nazwij aplikację ComposeTutorial i kliknąć Zakończ. Domyślny szablon zawiera już elementy Compose, ale w tym samouczku utworzysz go krok po kroku krok po kroku.
Najpierw wyświetl komunikat „Hello world”, przez dodanie elementu tekstowego wewnątrz
Metoda onCreate
. Można to zrobić przez zdefiniowanie treści
blokować i wywoływać metodę
Text
.
Blok setContent
definiuje układ aktywności,
funkcji kompozycyjnej. Funkcje kompozycyjne mogą być wywoływane tylko z innych funkcji kompozycyjnych
funkcji.
Jetpack Compose wykorzystuje wtyczkę kompilatora Kotlin, aby przekształcić te funkcje kompozycyjne w
elementów interfejsu aplikacji. Na przykład funkcja Text
kompozycyjna
która jest zdefiniowana przez bibliotekę interfejsu Compose, wyświetla na ekranie etykietę tekstową.
import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text("Hello world!") } } }
Zdefiniuj funkcję kompozycyjną
Aby umożliwić funkcji kompozycyjnej, dodaj adnotację @Composable
.
Aby to wypróbować, zdefiniuj funkcję MessageCard
, która jest
przekazuje nazwę i używa jej do skonfigurowania elementu tekstowego.
// ... import androidx.compose.runtime.Composable class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MessageCard("Android") } } } @Composable fun MessageCard(name: String) { Text(text = "Hello $name!") }
Podgląd funkcji w Android Studio
Adnotacja @Preview
umożliwia wyświetlenie podglądu funkcji kompozycyjnych na Androidzie.
Studio bez konieczności kompilowania i instalowania aplikacji na urządzeniu z Androidem czy w emulatorze.
adnotacji należy używać w funkcji kompozycyjnej, która nie przyjmuje parametrów. Do tego celu
Z tego powodu nie można wyświetlić podglądu funkcji MessageCard
bezpośrednio. Zamiast tego utwórz drugą funkcję o nazwie
PreviewMessageCard
, który wywołuje
MessageCard
z odpowiednim parametrem. Dodaj parametr
@Preview
adnotacja przed
@Composable
// ... import androidx.compose.ui.tooling.preview.Preview @Composable fun MessageCard(name: String) { Text(text = "Hello $name!") } @Preview @Composable fun PreviewMessageCard() { MessageCard("Android") }
Ponownie utwórz projekt. Aplikacja się nie zmienia,
Funkcja PreviewMessageCard
nie jest nigdzie wywoływana,
Android Studio dodaje okno podglądu, które można rozwinąć, klikając podział
(projekt/kod). To okno pokazuje podgląd elementów interfejsu utworzonych przez funkcję kompozycyjnej
funkcje oznaczone adnotacją @Preview
. Aby zaktualizować
wyświetlić podgląd w dowolnym momencie, kliknij przycisk odświeżania u góry okna podglądu.
import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text("Hello world!") } } }
// ... import androidx.compose.runtime.Composable class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MessageCard("Android") } } } @Composable fun MessageCard(name: String) { Text(text = "Hello $name!") }
// ... import androidx.compose.ui.tooling.preview.Preview @Composable fun MessageCard(name: String) { Text(text = "Hello $name!") } @Preview @Composable fun PreviewMessageCard() { MessageCard("Android") }
Lekcja 2. Układy
Elementy interfejsu są hierarchiczne – elementy znajdują się w innych elementach. W przypadku tworzenia wiadomości stworzyć hierarchię interfejsu, wywołując funkcje kompozycyjne z innych funkcji tego typu.
Dodaj wiele tekstów
Masz już gotową pierwszą funkcję kompozycyjną i podgląd. Aby odkryć więcej funkcji Jetpack Compose utworzysz prosty ekran z listą wiadomości, które który można rozwinąć przy użyciu animacji.
Na początek wzbogać wiadomość, dodając do niej imię i nazwisko autora oraz
treść wiadomości. Musisz najpierw zmienić parametr kompozycji, by zaakceptować
Message
obiekt zamiast
String
i dodaj kolejny
Funkcja Text
do tworzenia w funkcji
MessageCard
kompozycyjne. Pamiętaj, aby zaktualizować podgląd
.
// ... class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MessageCard(Message("Android", "Jetpack Compose")) } } } data class Message(val author: String, val body: String) @Composable fun MessageCard(msg: Message) { Text(text = msg.author) Text(text = msg.body) } @Preview @Composable fun PreviewMessageCard() { MessageCard( msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!") ) }
Ten kod tworzy 2 elementy tekstowe w widoku treści. Ponieważ jednak nie podano (informacje o ich rozmieszczeniu, elementy tekstowe są nakładane na siebie, przez co tekst jest nieczytelny.
Za pomocą kolumny
// ... import androidx.compose.foundation.layout.Column @Composable fun MessageCard(msg: Message) { Column { Text(text = msg.author) Text(text = msg.body) } }
Dodaj element obrazu
Wzbogać kartę wiadomości, dodając zdjęcie profilowe nadawcy. Użyj
Menedżer zasobów
aby zaimportować obraz z biblioteki zdjęć, lub użyj tego. Dodaj
Row
musi mieć dobrze zorganizowaną strukturę i
Image
elementu kompozycyjnego.
// ... import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.ui.res.painterResource @Composable fun MessageCard(msg: Message) { Row { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = "Contact profile picture", ) Column { Text(text = msg.author) Text(text = msg.body) } } }
Konfigurowanie układu
Układ wiadomości ma odpowiednią strukturę, ale jej elementy nie są odpowiednio rozmieszczone, za duży! Do dekorowania lub konfigurowania funkcji kompozycyjnego funkcja Utwórz używa modyfikatorów. Ta umożliwiają zmianę rozmiaru, układu i wyglądu elementu kompozycyjnego oraz dodawanie interakcji wysokiego poziomu. na przykład przez umożliwienie klikania elementu. Możesz je łączyć w sieci, aby tworzyć bardziej rozbudowane kompozycje. Czego używasz inne, aby ulepszyć układ.
// ... import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp @Composable fun MessageCard(msg: Message) { // Add padding around our message Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = "Contact profile picture", modifier = Modifier // Set image size to 40 dp .size(40.dp) // Clip image to be shaped as a circle .clip(CircleShape) ) // Add a horizontal space between the image and the column Spacer(modifier = Modifier.width(8.dp)) Column { Text(text = msg.author) // Add a vertical space between the author and message texts Spacer(modifier = Modifier.height(4.dp)) Text(text = msg.body) } } }
// ... class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MessageCard(Message("Android", "Jetpack Compose")) } } } data class Message(val author: String, val body: String) @Composable fun MessageCard(msg: Message) { Text(text = msg.author) Text(text = msg.body) } @Preview @Composable fun PreviewMessageCard() { MessageCard( msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!") ) }
// ... import androidx.compose.foundation.layout.Column @Composable fun MessageCard(msg: Message) { Column { Text(text = msg.author) Text(text = msg.body) } }
// ... import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.ui.res.painterResource @Composable fun MessageCard(msg: Message) { Row { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = "Contact profile picture", ) Column { Text(text = msg.author) Text(text = msg.body) } } }
// ... import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp @Composable fun MessageCard(msg: Message) { // Add padding around our message Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = "Contact profile picture", modifier = Modifier // Set image size to 40 dp .size(40.dp) // Clip image to be shaped as a circle .clip(CircleShape) ) // Add a horizontal space between the image and the column Spacer(modifier = Modifier.width(8.dp)) Column { Text(text = msg.author) // Add a vertical space between the author and message texts Spacer(modifier = Modifier.height(4.dp)) Text(text = msg.body) } } }
Lekcja 3. Styl Material Design
Interfejs Compose został stworzony zgodnie z zasadami Material Design. Wiele elementów interfejsu zawiera Material Design gotowe do rozpakowania. Podczas tej lekcji dostosujesz styl aplikacji do stylu Material Design. widżety.
Zastosuj styl Material Design
Twój projekt wiadomości ma teraz układ, ale nie wygląda jeszcze świetnie.
W Jetpack Compose możesz wdrożyć interfejs Material Design 3 i jego elementów interfejsu
. Poprawisz wygląd naszej MessageCard
w stylu Material Design.
Aby rozpocząć, opakuj funkcję MessageCard
za pomocą funkcji
W Twoim projekcie ComposeTutorialTheme
został utworzony motyw Material Design,
oraz Surface
.
Zrób to zarówno tutaj, jak i w sekcji @Preview
setContent
. Jeśli to zrobisz, Twoje kompozycje
dziedziczenie stylów określonych w motywie aplikacji, co zapewnia spójność jej treści.
Material Design opiera się na 3 filarach: Color
,
Typography
i Shape
.
Możesz je dodawać pojedynczo.
Uwaga: szablon „Puste działania związane z tworzeniem wiadomości” generuje domyślny motyw projektu,
pozwala dostosować
MaterialTheme
.
Jeśli projekt został nazwany inaczej niż
ComposeSamouczek, swój motyw niestandardowy znajdziesz w
Theme.kt
w
ui.theme
podpakiet.
// ... class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ComposeTutorialTheme { Surface(modifier = Modifier.fillMaxSize()) { MessageCard(Message("Android", "Jetpack Compose")) } } } } } @Preview @Composable fun PreviewMessageCard() { ComposeTutorialTheme { Surface { MessageCard( msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!") ) } } }
Kolor
Użyj MaterialTheme.colorScheme
, aby dodać styl do kolorów z
motyw opakowany. Tych wartości możesz używać z motywu wszędzie tam, gdzie potrzebny jest kolor. W tym przykładzie użyto dynamicznego motywu kolorystycznego (określonego przez preferencje urządzenia).
Aby to zmienić, możesz ustawić wartość dynamicColor
na false
w pliku MaterialTheme.kt
.
Zmień styl tytułu i dodaj obramowanie do zdjęcia.
// ... import androidx.compose.foundation.border import androidx.compose.material3.MaterialTheme @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary ) Spacer(modifier = Modifier.height(4.dp)) Text(text = msg.body) } } }
Typografia
Style typografii materiału są dostępne w językach: MaterialTheme
,
po prostu dodaj je do elementów kompozycyjnych Text
.
// ... @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Text( text = msg.body, style = MaterialTheme.typography.bodyMedium ) } } }
Kształt
Dzięki Shape
możesz wprowadzić ostatnie poprawki. Najpierw zapakuj plik
treść wiadomości wokół znaku
Surface
kompozycyjne. Umożliwia to dostosowanie parametru
kształt i wysokość wiadomości. Do wiadomości dodano też dopełnienie, aby zapewnić lepszy układ.
// ... import androidx.compose.material3.Surface @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) { Text( text = msg.body, modifier = Modifier.padding(all = 4.dp), style = MaterialTheme.typography.bodyMedium ) } } } }
Włącz ciemny motyw
Ciemny motyw (lub tryb nocny), by uniknąć jasnego ekranu, zwłaszcza w nocy, lub po prostu oszczędzać baterii urządzenia. Dzięki obsłudze Material Design Jetpack Compose poradzi sobie z ciemnością domyślny motyw. Kolory, tekst i tła w stylu Material Design dostosuje się do ciemnego tła.
Możesz utworzyć wiele podglądów w pliku jako oddzielne funkcje lub dodać kilka do tej samej funkcji.
Dodaj nową adnotację do podglądu i włącz tryb nocny.
// ... import android.content.res.Configuration @Preview(name = "Light Mode") @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true, name = "Dark Mode" ) @Composable fun PreviewMessageCard() { ComposeTutorialTheme { Surface { MessageCard( msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!") ) } } }
Dobór kolorów dla jasnego i ciemnego motywu jest określony w wygenerowanym IDE
Theme.kt
.
Na razie udało Ci się utworzyć element interfejsu wiadomości, w którym wyświetla się obraz i 2 teksty z różnymi będzie dobrze wyglądać zarówno w jasnych, jak i ciemnych motywach.
// ... import android.content.res.Configuration @Preview(name = "Light Mode") @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true, name = "Dark Mode" ) @Composable fun PreviewMessageCard() { ComposeTutorialTheme { Surface { MessageCard( msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!") ) } } }
// ... class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ComposeTutorialTheme { Surface(modifier = Modifier.fillMaxSize()) { MessageCard(Message("Android", "Jetpack Compose")) } } } } } @Preview @Composable fun PreviewMessageCard() { ComposeTutorialTheme { Surface { MessageCard( msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!") ) } } }
// ... import androidx.compose.foundation.border import androidx.compose.material3.MaterialTheme @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary ) Spacer(modifier = Modifier.height(4.dp)) Text(text = msg.body) } } }
// ... @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Text( text = msg.body, style = MaterialTheme.typography.bodyMedium ) } } }
// ... import androidx.compose.material3.Surface @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) { Text( text = msg.body, modifier = Modifier.padding(all = 4.dp), style = MaterialTheme.typography.bodyMedium ) } } } }
// ... import android.content.res.Configuration @Preview(name = "Light Mode") @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true, name = "Dark Mode" ) @Composable fun PreviewMessageCard() { ComposeTutorialTheme { Surface { MessageCard( msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!") ) } } }
Lekcja 4. Listy i animacje
Listy i animacje są wszędzie w aplikacjach. Z tej lekcji dowiesz się, jak Ułatwia tworzenie list i dodawanie animacji.
Tworzenie listy wiadomości
Czat z jedną wiadomością wydaje się trochę samotny, więc zmienimy go tak, aby zawierał więcej niż
jedną wiadomość. Musisz utworzyć funkcję Conversation
z kilkoma wiadomościami. W tym przypadku użyj funkcji Utwórz
LazyColumn
i
.
LazyRow
Te kompozycje renderują tylko elementy
są widoczne na ekranie, więc bardzo dobrze sprawdzają się w przypadku długich list.
Jak widać w tym fragmencie kodu, LazyColumn
zawiera parametr
items
dziecko. Trwa to
List
jako parametr i jego wartość lambda
otrzymuje parametr o nazwie message
(moglibyśmy mieć
nazwaliśmy go dowolną nazwą). Jest to przypadek Message
.
Krótko mówiąc, funkcja lambda jest wywoływana w przypadku każdego elementu
List
Skopiuj
przykładowy zbiór danych
w swoim projekcie, aby przyspieszyć wczytywanie rozmowy.
// ... import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @Composable fun Conversation(messages: List<Message>) { LazyColumn { items(messages) { message -> MessageCard(message) } } } @Preview @Composable fun PreviewConversation() { ComposeTutorialTheme { Conversation(SampleData.conversationSample) } }
Animuj wiadomości podczas rozwijania
Rozmowa staje się coraz ciekawsza. Czas pobawić się animacjami. Dodajesz
możliwość rozwijania wiadomości w celu wyświetlenia dłuższej wiadomości, animowanie rozmiaru wiadomości i
kolor tła. Aby zapisać ten stan lokalnego interfejsu użytkownika, musisz sprawdzać, czy wiadomość
została rozszerzona, czy nie. Aby śledzić tę zmianę stanu, musisz użyć funkcji
remember
i
mutableStateOf
Funkcje kompozycyjne mogą przechowywać w pamięci stan lokalny za pomocą funkcji
remember
i śledź zmiany w wartości przekazywanej do
mutableStateOf
Elementy kompozycyjne (i ich dzieci) korzystające z funkcji
ten stan jest automatycznie odświeżany po zaktualizowaniu wartości. Jest to tzw.
zmianę kompozycji.
Przy użyciu interfejsów API stanu, takich jak remember
czy
mutableStateOf
, każda zmiana stanu powoduje automatyczną aktualizację interfejsu użytkownika.
Uwaga: aby poprawnie korzystać z modelu Kotlin, musisz dodać następujące elementy
składni właściwości delegowanej (słowo kluczowe by
). Doda je klawisze Alt+Enter lub Option+Enter
dla Ciebie.
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
// ... import androidx.compose.foundation.clickable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ComposeTutorialTheme { Conversation(SampleData.conversationSample) } } } } @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) // We keep track if the message is expanded or not in this // variable var isExpanded by remember { mutableStateOf(false) } // We toggle the isExpanded variable when we click on this Column Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Surface( shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp, ) { Text( text = msg.body, modifier = Modifier.padding(all = 4.dp), // If the message is expanded, we display all its content // otherwise we only display the first line maxLines = if (isExpanded) Int.MAX_VALUE else 1, style = MaterialTheme.typography.bodyMedium ) } } } }
Teraz możesz zmienić tło treści wiadomości na podstawie
isExpanded
, gdy klikamy wiadomość. Za pomocą
clickable
modyfikator do obsługi zdarzeń kliknięć w tabeli
kompozycyjne. Zamiast zmieniać kolor tła
Surface
, kolor tła zostanie animowany przez
stopniowo modyfikując jego wartość z
MaterialTheme.colorScheme.surface
do
MaterialTheme.colorScheme.primary
i na odwrót. Aby to zrobić:
użyjesz funkcji animateColorAsState
. Na koniec
będzie używać modyfikatora animateContentSize
do animacji
pozwala płynnie dostosowywać rozmiar kontenera wiadomości:
// ... import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateContentSize @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) // We keep track if the message is expanded or not in this // variable var isExpanded by remember { mutableStateOf(false) } // surfaceColor will be updated gradually from one color to the other val surfaceColor by animateColorAsState( if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface, ) // We toggle the isExpanded variable when we click on this Column Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Surface( shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp, // surfaceColor color will be changing gradually from primary to surface color = surfaceColor, // animateContentSize will change the Surface size gradually modifier = Modifier.animateContentSize().padding(1.dp) ) { Text( text = msg.body, modifier = Modifier.padding(all = 4.dp), // If the message is expanded, we display all its content // otherwise we only display the first line maxLines = if (isExpanded) Int.MAX_VALUE else 1, style = MaterialTheme.typography.bodyMedium ) } } } }
// ... import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @Composable fun Conversation(messages: List<Message>) { LazyColumn { items(messages) { message -> MessageCard(message) } } } @Preview @Composable fun PreviewConversation() { ComposeTutorialTheme { Conversation(SampleData.conversationSample) } }
// ... import androidx.compose.foundation.clickable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ComposeTutorialTheme { Conversation(SampleData.conversationSample) } } } } @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) // We keep track if the message is expanded or not in this // variable var isExpanded by remember { mutableStateOf(false) } // We toggle the isExpanded variable when we click on this Column Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Surface( shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp, ) { Text( text = msg.body, modifier = Modifier.padding(all = 4.dp), // If the message is expanded, we display all its content // otherwise we only display the first line maxLines = if (isExpanded) Int.MAX_VALUE else 1, style = MaterialTheme.typography.bodyMedium ) } } } }
// ... import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateContentSize @Composable fun MessageCard(msg: Message) { Row(modifier = Modifier.padding(all = 8.dp)) { Image( painter = painterResource(R.drawable.profile_picture), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) // We keep track if the message is expanded or not in this // variable var isExpanded by remember { mutableStateOf(false) } // surfaceColor will be updated gradually from one color to the other val surfaceColor by animateColorAsState( if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface, ) // We toggle the isExpanded variable when we click on this Column Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) { Text( text = msg.author, color = MaterialTheme.colorScheme.secondary, style = MaterialTheme.typography.titleSmall ) Spacer(modifier = Modifier.height(4.dp)) Surface( shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp, // surfaceColor color will be changing gradually from primary to surface color = surfaceColor, // animateContentSize will change the Surface size gradually modifier = Modifier.animateContentSize().padding(1.dp) ) { Text( text = msg.body, modifier = Modifier.padding(all = 4.dp), // If the message is expanded, we display all its content // otherwise we only display the first line maxLines = if (isExpanded) Int.MAX_VALUE else 1, style = MaterialTheme.typography.bodyMedium ) } } } }
Dalsze kroki
Gratulujemy! Samouczek dotyczący tworzenia wiadomości został ukończony. Udało Ci się stworzyć prosty ekran czatu, który efektywnie wyświetla listę rozwijanych i animowanych wiadomości zawierających obrazy oraz tekst. Zaprojektowano ją zgodnie z zasadami Material Design z ciemnym motywem i podglądami – a wszystko to w mniej niż 100 wierszach kodu.
Oto czego już się dowiedziałeś(-aś):
- Definiowanie funkcji kompozycyjnych
- Dodawanie różnych elementów do funkcji kompozycyjnej
- Tworzenie struktury komponentu interfejsu za pomocą funkcji kompozycyjnych układu
- Rozszerzanie funkcji kompozycyjnych za pomocą modyfikatorów
- Tworzenie skutecznej listy
- Śledzenie stanu i modyfikowanie go
- Dodawanie interakcji użytkownika do funkcji kompozycyjnej
- Animowanie wiadomości przy ich rozwijaniu
Jeśli chcesz dowiedzieć się więcej o niektórych z poniższych etapów, zapoznaj się z materiałami poniżej.