Anleitung

Jetpack Compose-Anleitung

Jetpack Compose ist ein modernes Toolkit zum Erstellen nativer Android-UIs. Jetpack Compose vereinfacht und beschleunigt die UI-Entwicklung für Android mit weniger Code, leistungsstarken Tools und intuitiven Kotlin-APIs.

In dieser Anleitung erstellen Sie eine einfache UI-Komponente mit deklarativen Funktionen. Sie werden weder XML-Layouts bearbeiten noch den Layout-Editor verwenden. Stattdessen rufen Sie zusammensetzbare Funktionen auf, um die gewünschten Elemente zu definieren. Der Compose-Compiler erledigt dann den Rest.

Vollständige Leseprobe
Vollständige Leseprobe

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

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 anzeigen
Vorschau ausblenden

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")
}
  
Vorschau anzeigen
Vorschau ausblenden

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“.

Vorschau einer zusammensetzbaren Funktion in 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!")
        }
    }
}
  
Vorschau anzeigen
Vorschau ausblenden
// ...
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 anzeigen
Vorschau ausblenden
// ...
import androidx.compose.ui.tooling.preview.Preview

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

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
Vorschau anzeigen
Vorschau ausblenden
Vorschau einer zusammensetzbaren Funktion in Android Studio

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

  
Vorschau anzeigen
Vorschau ausblenden

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

Mit der Funktion Column können Sie Elemente vertikal anordnen. Fügen Sie der Funktion MessageCard Column hinzu.
Mit Row können Sie Elemente horizontal anordnen und Box zum Stapeln von Elementen.

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

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

Vorschau anzeigen
Vorschau ausblenden

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)
        }
  
    }
  
}
  
Vorschau anzeigen
Vorschau ausblenden

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)
        }
    }
}
  
Vorschau anzeigen
Vorschau ausblenden
// ...

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

  
Vorschau anzeigen
Vorschau ausblenden
Vorschau von zwei sich überschneidenden Textzusammensetzbaren
// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

Vorschau anzeigen
Vorschau ausblenden
// ...
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)
        }
  
    }
  
}
  
Vorschau anzeigen
Vorschau ausblenden
// ...
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)
        }
    }
}
  
Vorschau anzeigen
Vorschau ausblenden

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


  
Vorschau anzeigen
Vorschau ausblenden

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

  
Vorschau anzeigen
Vorschau ausblenden

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

  
Vorschau anzeigen
Vorschau ausblenden

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

  
Vorschau anzeigen
Vorschau ausblenden

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

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!")
      )
    }
   }
}
  
Vorschau anzeigen
Vorschau ausblenden
// ...

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


  
Vorschau anzeigen
Vorschau ausblenden
// ...
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)
       }
   }
}

  
Vorschau anzeigen
Vorschau ausblenden
// ...

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

  
Vorschau anzeigen
Vorschau ausblenden
// ...
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
               )
           }
       }
   }
}

  
Vorschau anzeigen
Vorschau ausblenden
// ...
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!")
      )
    }
   }
}
  
Vorschau anzeigen
Vorschau ausblenden
Vorschau mit hellen und dunklen zusammensetzbaren Funktionen.

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

  
Vorschau anzeigen
Vorschau ausblenden

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

  
Vorschau anzeigen
Vorschau ausblenden

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

  
Vorschau anzeigen
Vorschau ausblenden
// ...
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)
    }
}

  
Vorschau anzeigen
Vorschau ausblenden
// ...
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
                )
            }
        }
    }
}

  
Vorschau anzeigen
Vorschau ausblenden
// ...
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
                )
            }
        }
    }
}

  
Vorschau anzeigen
Vorschau ausblenden

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.

Nächste Schritte

Einrichtung
Nachdem Sie die Anleitung zum Schreiben einer Nachricht abgeschlossen haben, können Sie nun mit der Funktion "Schreiben" beginnen.
Weg
Werfen Sie einen Blick auf unsere ausgewählten Codelabs und Videos, die Ihnen helfen, Jetpack Compose zu erlernen und zu beherrschen.