Samouczek

Samouczek w Jetpack Compose

Jetpack Compose to nowoczesny pakiet narzędzi do tworzenia natywnego interfejsu Androida. Jetpack Compose upraszcza i przyspiesza tworzenie UI na Androidzie przy użyciu mniejszej ilości kodu, zaawansowanych narzędzi i intuicyjnych interfejsów API Kotlin.

W tym samouczku utworzysz prosty komponent UI z funkcjami deklaratywnymi. Nie będziesz edytować żadnych układów XML ani korzystać z Edytora układów. Zamiast tego będziesz wywoływać funkcje kompozycyjne, które definiują potrzebne elementy, a kompilator Compose zajmie się resztą.

Pełny podgląd
Pełny podgląd

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!")
        }
    }
}
  
pokaż podgląd
ukryj podgląd

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!")
}

  
pokaż podgląd
ukryj podgląd

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")
}
  
pokaż podgląd
ukryj podgląd

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.

Podgląd funkcji kompozycyjnej w Android Studio
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!")
        }
    }
}
  
pokaż podgląd
ukryj podgląd
// ...
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!")
}

  
pokaż podgląd
ukryj podgląd
// ...
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
pokaż podgląd
ukryj podgląd
Podgląd funkcji kompozycyjnej w Android Studio

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!")
    )
}

  
pokaż podgląd
ukryj podgląd

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

Column umożliwia rozmieszczanie elementów w pionie. Dodaj Column do MessageCard.
Możesz użyć Row, aby rozmieścić elementy w poziomie, Box do stosów elementów.

// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
pokaż podgląd
ukryj podgląd

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)
        }
  
    }
  
}
  
pokaż podgląd
ukryj podgląd

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)
        }
    }
}
  
pokaż podgląd
ukryj 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!")
    )
}

  
pokaż podgląd
ukryj podgląd
Podgląd dwóch nakładających się elementów kompozycyjnych tekstu
// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
pokaż podgląd
ukryj podgląd
// ...
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)
        }
  
    }
  
}
  
pokaż podgląd
ukryj podgląd
// ...
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)
        }
    }
}
  
pokaż podgląd
ukryj podgląd

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!")
            )
        }
    }
}


  
pokaż podgląd
ukryj podgląd

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)
       }
   }
}

  
pokaż podgląd
ukryj podgląd

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
           )
       }
   }
}

  
pokaż podgląd
ukryj podgląd

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
               )
           }
       }
   }
}

  
pokaż podgląd
ukryj podgląd

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!")
      )
    }
   }
}
  
pokaż podgląd
ukryj podgląd

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!")
      )
    }
   }
}
  
pokaż podgląd
ukryj podgląd
// ...

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!")
            )
        }
    }
}


  
pokaż podgląd
ukryj podgląd
// ...
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)
       }
   }
}

  
pokaż podgląd
ukryj podgląd
// ...

@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
           )
       }
   }
}

  
pokaż podgląd
ukryj podgląd
// ...
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
               )
           }
       }
   }
}

  
pokaż podgląd
ukryj podgląd
// ...
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!")
      )
    }
   }
}
  
pokaż podgląd
ukryj podgląd
Podgląd przedstawiający kompozycje z motywem jasnym i ciemnym.

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)
    }
}

  
pokaż podgląd
ukryj podgląd

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
                )
            }
        }
    }
}

  
pokaż podgląd
ukryj podgląd

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
                )
            }
        }
    }
}

  
pokaż podgląd
ukryj podgląd
// ...
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)
    }
}

  
pokaż podgląd
ukryj podgląd
// ...
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
                )
            }
        }
    }
}

  
pokaż podgląd
ukryj podgląd
// ...
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
                )
            }
        }
    }
}

  
pokaż podgląd
ukryj podgląd

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.

Dalsze kroki

Konfiguracja
Samouczek tworzenia wiadomości został ukończony, możesz więc zacząć tworzyć w tej usłudze.
Ścieżka
Poznaj wyselekcjonowaną ścieżkę z programami i filmami, które pomogą Ci poznać i opanować Jetpack Compose.