Lektion 1: Zusammensetzbare Funktionen
Jetpack Compose basiert auf zusammensetzbaren Funktionen. Mit diesen Funktionen können Sie die UI Ihrer App programmatisch definieren, indem Sie ihr Aussehen beschreiben und Datenabhängigkeiten angeben, anstatt sich auf den Prozess der UI-Erstellung zu konzentrieren (Initialisieren eines Elements, Anhängen an ein übergeordnetes Element usw.). Wenn Sie eine zusammensetzbare Funktion erstellen möchten, fügen Sie dem Funktionsnamen einfach die Annotation @Composable
hinzu.
Textelement hinzufügen
Lade zuerst die neueste Version von Android Studio herunter und erstelle eine App, indem du Neues Projekt und dann in der Kategorie Smartphone und Tablet die Option Leere Aktivität auswählst. Nennen Sie die Anwendung ComposeTutorial und klicken Sie auf Finish (Fertigstellen). Die Standardvorlage enthält bereits einige Compose-Elemente. In dieser Anleitung werden Sie sie jedoch Schritt für Schritt erstellen.
Blende zuerst einen „Hallo Welt!“-Text ein. Füge dazu ein Textelement in die Methode onCreate
ein. Dazu definieren Sie einen Inhaltsblock und rufen die zusammensetzbare Funktion
Text
auf. Der setContent
-Block definiert das Layout der Aktivität, in dem zusammensetzbare Funktionen aufgerufen werden. Zusammensetzbare Funktionen können nur von anderen zusammensetzbaren Funktionen aufgerufen werden.
Jetpack Compose verwendet ein Kotlin-Compiler-Plug-in, um diese zusammensetzbaren Funktionen in die UI-Elemente der App umzuwandeln. Mit der zusammensetzbaren Funktion Text
, die in der UI-Bibliothek „Compose“ definiert wird, wird beispielsweise ein Textlabel auf dem Bildschirm angezeigt.
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!") } } }
Eine zusammensetzbare Funktion definieren
Wenn Sie eine Funktion zusammensetzbar machen möchten, fügen Sie die Annotation @Composable
hinzu.
Definieren Sie zum Ausprobieren eine MessageCard
-Funktion, der ein Name übergeben wird und mit der das Textelement konfiguriert wird.
// ... 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!") }
Vorschau der Funktion in Android Studio ansehen
Mit der Annotation @Preview
können Sie eine Vorschau Ihrer zusammensetzbaren Funktionen in Android Studio ansehen, ohne die App auf einem Android-Gerät oder in einem Emulator erstellen und installieren zu müssen. Die Annotation muss für eine zusammensetzbare Funktion verwendet werden, die keine Parameter annimmt. Daher ist eine direkte Vorschau der Funktion MessageCard
nicht möglich. Erstellen Sie stattdessen eine zweite Funktion mit dem Namen PreviewMessageCard
, die MessageCard
mit einem entsprechenden Parameter aufruft. Fügen Sie die Annotation @Preview
vor @Composable
ein.
// ... import androidx.compose.ui.tooling.preview.Preview @Composable fun MessageCard(name: String) { Text(text = "Hello $name!") } @Preview @Composable fun PreviewMessageCard() { MessageCard("Android") }
Erstellen Sie Ihr Projekt neu. Die App selbst ändert sich nicht, da die neue PreviewMessageCard
-Funktion nirgendwo aufgerufen wird. Android Studio fügt jedoch ein Vorschaufenster hinzu, das Sie durch Klicken auf die geteilte Ansicht (Design/Code) maximieren können. In diesem Fenster wird eine Vorschau der UI-Elemente angezeigt, die von zusammensetzbaren Funktionen erstellt wurden, die mit der Anmerkung @Preview
gekennzeichnet sind. Sie können die Vorschauen jederzeit aktualisieren. Klicken Sie dazu oben im Vorschaufenster auf die Schaltfläche „Aktualisieren“.
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") }
Lektion 2: Layouts
UI-Elemente sind hierarchisch aufgebaut, wobei die Elemente in anderen Elementen enthalten sind. In „Compose“ erstellen Sie eine UI-Hierarchie, indem Sie zusammensetzbare Funktionen aus anderen zusammensetzbaren Funktionen aufrufen.
Mehrere Texte hinzufügen
Bisher haben Sie Ihre erste zusammensetzbare Funktion und Vorschau erstellt. Wenn Sie weitere Jetpack Compose-Funktionen kennenlernen möchten, erstellen Sie einen einfachen Nachrichtenbildschirm, der eine Liste von Nachrichten enthält, die mit Animationen erweitert werden kann.
Ergänzen Sie die Nachricht zuerst, indem Sie den Namen des Autors und den Inhalt der Nachricht anzeigen lassen. Sie müssen zuerst den Parameter für die zusammensetzbare Funktion so ändern, dass ein Message
-Objekt anstelle eines String
-Objekts akzeptiert wird. Fügen Sie dann innerhalb der zusammensetzbaren Funktion MessageCard
eine weitere zusammensetzbare Funktion Text
hinzu. Aktualisieren Sie auch die Vorschau.
// ... 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!") ) }
Mit diesem Code werden innerhalb der Inhaltsansicht zwei Textelemente erstellt. Da du jedoch keine Informationen zur Anordnung angegeben hast, werden die Textelemente übereinander gezeichnet, wodurch der Text unlesbar wird.
Verwenden einer Spalte
// ... import androidx.compose.foundation.layout.Column @Composable fun MessageCard(msg: Message) { Column { Text(text = msg.author) Text(text = msg.body) } }
Bildelement hinzufügen
Fügen Sie Ihrer Nachrichtenkarte ein Profilbild des Absenders hinzu. Verwenden Sie Resource Manager, um ein Bild aus Ihrer Fotogalerie zu importieren, oder verwenden Sie dieses hier. Fügen Sie eine zusammensetzbare Funktion Row
hinzu, um ein gut strukturiertes Design und eine darin enthaltene zusammensetzbare Funktion
Image
zu erhalten.
// ... 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) } } }
Layout konfigurieren
Ihr Mitteilungslayout hat die richtige Struktur, aber die Elemente sind nicht gut angeordnet und das Bild ist zu groß. Wenn Sie eine zusammensetzbare Funktion gestalten oder konfigurieren möchten, werden in der Funktion Modifikatoren verwendet. Damit können Sie Größe, Layout und Darstellung der zusammensetzbaren Funktion ändern oder allgemeine Interaktionen hinzufügen, z. B. ein Element anklickbar machen. Sie können sie verketten, um nützlichere zusammensetzbare Funktionen zu erstellen. Einige verwenden Sie, um das Layout zu verbessern.
// ... 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) } } }
Lektion 3: Material Design
Compose wurde zur Unterstützung von Material Design-Prinzipien entwickelt. Viele seiner UI-Elemente implementieren Material Design standardmäßig. In dieser Lektion gestalten Sie Ihre App mit Material Design-Widgets.
Material Design nutzen
Ihr Mitteilungsdesign hat jetzt ein Layout, aber es sieht noch nicht gut aus.
Jetpack Compose bietet eine sofortige Implementierung von Material Design 3 und seinen UI-Elementen. Mit dem Material Design-Stil verbessern Sie das Erscheinungsbild unserer zusammensetzbaren Funktion MessageCard
.
Verpacken Sie die Funktion MessageCard
zuerst mit dem in Ihrem Projekt erstellten Material Theme (ComposeTutorialTheme
) sowie einem Surface
.
Tun Sie dies sowohl in der @Preview
- als auch in der setContent
-Funktion. Dadurch übernehmen die zusammensetzbaren Funktionen die im Design Ihrer App definierten Stile und sorgen so für Konsistenz in der gesamten App.
Material Design stützt sich auf drei Säulen: Color
, Typography
und Shape
.
Sie fügen sie nacheinander hinzu.
Hinweis:Mit der Vorlage „Empty Compose Activity“ wird ein Standarddesign für Ihr Projekt generiert, in dem Sie
MaterialTheme
anpassen können.
Wenn Sie Ihr Projekt anders benannt haben als ComposeTutorial, finden Sie Ihr benutzerdefiniertes Design in der Datei Theme.kt
im Teilpaket ui.theme
.
// ... 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!") ) } } }
Farbe
Mit MaterialTheme.colorScheme
können Sie Farben aus dem umschlossenen Design gestalten. Sie können diese Werte aus dem Design überall verwenden, wo eine Farbe benötigt wird. In diesem Beispiel werden dynamische Designfarben verwendet, die durch Geräteeinstellungen definiert sind.
Sie können dies in der Datei MaterialTheme.kt
durch dynamicColor
auf false
ändern.
Gestalten Sie den Titel und fügen Sie dem Bild einen Rahmen hinzu.
// ... 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) } } }
Typografie
Material Typography-Stile sind in MaterialTheme
verfügbar. Fügen Sie sie einfach den Text
zusammensetzbaren Funktionen hinzu.
// ... @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 ) } } }
Form
Mit Shape
kannst du noch den letzten Schliff verleihen. Setzen Sie zuerst den Text der Nachricht um eine zusammensetzbare Funktion
Surface
. Auf diese Weise können Sie Form und Höhe des Nachrichtentexts anpassen. Außerdem wird die Nachricht mit einem Abstand versehen, um das Layout zu verbessern.
// ... 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 ) } } } }
Dunkles Design aktivieren
Das dunkle Design bzw. der Nachtmodus kann aktiviert werden, um ein helles Display zu vermeiden, insbesondere nachts, oder einfach, um den Akku des Geräts zu schonen. Dank der Material Design-Unterstützung kann Jetpack Compose das dunkle Design standardmäßig verarbeiten. Wenn Sie Material Design-Farben, Texte und Hintergründe verwenden, passen sie sich automatisch an den dunklen Hintergrund an.
Sie können mehrere Vorschauen in Ihrer Datei als separate Funktionen erstellen oder derselben Funktion mehrere Annotationen hinzufügen.
Füge einen neuen Vorschauanmerkung hinzu und aktiviere den Nachtmodus.
// ... 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!") ) } } }
Die Farbauswahl für das helle und das dunkle Design wird in der von der IDE generierten Datei Theme.kt
definiert.
Bisher haben Sie ein UI-Element für Mitteilungen erstellt, das ein Bild und zwei Texte in verschiedenen Stilen anzeigt. Es sieht sowohl im hellen als auch im dunklen Design gut aus.
// ... 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!") ) } } }
Lektion 4: Listen und Animationen
Listen und Animationen sind überall in Apps zu finden. In dieser Lektion erfahren Sie, wie Sie mit der Funktion „Compose“ ganz einfach Listen erstellen und Animationen hinzufügen.
Liste mit Nachrichten erstellen
Ein Chat mit einer Nachricht fühlt sich ein wenig einsam an. Wir ändern daher die Unterhaltung so, dass sie mehr als eine Nachricht enthält. Sie müssen eine Conversation
-Funktion erstellen, mit der mehrere Nachrichten angezeigt werden. Verwenden Sie für diesen Anwendungsfall
LazyColumn
und
LazyRow
von Compose. Diese zusammensetzbaren Funktionen rendern nur die Elemente, die auf dem Bildschirm sichtbar sind. Sie wurden daher für lange Listen sehr effizient entwickelt.
In diesem Code-Snippet sehen Sie, dass LazyColumn
ein untergeordnetes items
-Element hat. Es nimmt einen List
als Parameter und seine Lambda-Funktion empfängt einen Parameter, den wir message
genannt haben (wir hätten ihm einen beliebigen Namen geben können), der eine Instanz von Message
ist.
Diese Lambda-Funktion wird für jedes Element der bereitgestellten List
aufgerufen. Kopieren Sie das Beispiel-Dataset in Ihr Projekt, um das Gespräch schnell zu starten.
// ... 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) } }
Nachrichten beim Maximieren animieren
Das Gespräch wird interessanter. Zeit, mit Animationen zu spielen! Sie werden die Möglichkeit hinzufügen, eine Nachricht zu maximieren, sodass eine längere Nachricht angezeigt wird. Dabei werden sowohl die Inhaltsgröße als auch die Hintergrundfarbe animiert. Zum Speichern dieses lokalen UI-Status müssen Sie im Auge behalten, ob eine Nachricht maximiert wurde oder nicht. Um diese Statusänderung zu verfolgen, müssen Sie die Funktionen remember
und mutableStateOf
verwenden.
Zusammensetzbare Funktionen können den lokalen Status mithilfe von remember
im Arbeitsspeicher speichern und Änderungen am Wert verfolgen, der an mutableStateOf
übergeben wird. Zusammensetzbare Funktionen (und ihre untergeordneten Elemente), die diesen Status verwenden, werden bei der Aktualisierung des Werts automatisch neu gezeichnet. Dies wird als Neuzusammensetzung bezeichnet.
Mithilfe der State APIs von Compose wie remember
und mutableStateOf
wird die UI bei jeder Statusänderung automatisch aktualisiert.
Hinweis:Sie müssen die folgenden Importe hinzufügen, um die delegierte Property-Syntax von Kotlin korrekt verwenden zu können (Keyword by
). Mit Alt + Eingabetaste oder Wahltaste + Eingabetaste werden diese automatisch eingefügt.
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 ) } } } }
Jetzt können Sie den Hintergrund des Nachrichteninhalts basierend auf isExpanded
ändern, wenn wir auf eine Nachricht klicken. Mit dem clickable
-Modifikator werden Klickereignisse in der zusammensetzbaren Funktion verarbeitet. Anstatt einfach die Hintergrundfarbe von Surface
zu wechseln, animieren Sie die Hintergrundfarbe, indem Sie ihren Wert nach und nach von MaterialTheme.colorScheme.surface
in MaterialTheme.colorScheme.primary
ändern und umgekehrt. Dazu verwenden Sie die Funktion animateColorAsState
. Schließlich verwenden Sie den animateContentSize
-Modifikator, um die Größe des Nachrichtencontainers reibungslos zu animieren:
// ... 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 ) } } } }
Nächste Schritte
Herzlichen Glückwunsch! Sie haben die Anleitung zum Schreiben einer Nachricht abgeschlossen. Sie haben einen einfachen Chatbildschirm erstellt, der effizient eine Liste von maximierbaren und animierten Nachrichten mit einem Bild und Text enthält. Diese wurden nach Material Design-Prinzipien mit einem dunklen Design und Vorschauen gestaltet – und das alles in weniger als 100 Codezeilen.
Sie haben bisher Folgendes gelernt:
- Zusammensetzbare Funktionen definieren
- Verschiedene Elemente in einer zusammensetzbaren Funktion hinzufügen
- UI-Komponente mit zusammensetzbaren Layout-Layouts strukturieren
- Zusammensetzbare Funktionen mithilfe von Modifikatoren erweitern
- Listen effizient erstellen
- Nachverfolgen des Status und Änderung
- Nutzerinteraktion zu einer zusammensetzbaren Funktion hinzufügen
- Maximieren und Animieren von Botschaften
Weitere Informationen zu einigen dieser Schritte finden Sie in den folgenden Ressourcen.