Tutorial

Tutorial su Jetpack Compose

Jetpack Compose è un toolkit moderno per la creazione di una UI nativa di Android. Jetpack Compose semplifica e accelera lo sviluppo di UI su Android con meno codice, strumenti potenti e API Kotlin intuitive.

In questo tutorial creerai un semplice componente dell'interfaccia utente con funzioni dichiarative. Non modificherai layout XML né utilizzerai l'Editor layout. Chiamerai le funzioni componibili per definire gli elementi che vuoi e il compilatore Compose farà il resto.

Anteprima completa
Anteprima completa

Lezione 1: Funzioni componibili

Jetpack Compose si basa su funzioni componibili. Queste funzioni ti consentono di definire la UI dell'app in modo programmatico, descrivendone l'aspetto e fornendo le dipendenze dei dati. invece che concentrarsi sul processo di creazione dell'interfaccia utente (inizializzazione di un elemento, allegandolo a un genitore e così via). Per creare una funzione componibile, è sufficiente aggiungere il metodo @Composable al nome della funzione.

Aggiungere un elemento di testo

Per iniziare, scarica la versione più recente di Android Studio e creare un'app selezionando Nuovo progetto e sotto Categoria Smartphone e tablet, seleziona Attività vuota. Assegna all'app il nome ComposeTutorial e fai clic su Fine. Il valore predefinito contiene già alcuni elementi Compose, ma in questo tutorial imparerai a per passo.

Per prima cosa, visualizza il messaggio "Hello world!". di testo aggiungendo un elemento di testo all'interno onCreate. Per farlo devi definire un contenuto bloccare e chiamare il Funzione componibile Text. La Il blocco setContent definisce il layout dell'attività in cui funzioni componibili. Le funzioni componibili possono essere chiamate solo da altre funzioni.

Jetpack Compose usa un plug-in del compilatore Kotlin per trasformare queste funzioni componibili nel elementi UI dell'app. Ad esempio, il componibile Text definita dalla libreria della UI di composizione mostra un'etichetta di testo sullo schermo.

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

Definire una funzione componibile

Per rendere componibile una funzione, aggiungi l'annotazione @Composable. Per fare una prova, definisci una funzione MessageCard che sia passa un nome e lo utilizza per configurare l'elemento di testo.

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

  
mostra anteprima
nascondi anteprima

Visualizza l'anteprima della funzione in Android Studio

L'annotazione @Preview ti consente di visualizzare l'anteprima delle funzioni componibili in Android Studio senza dover creare e installare l'app su un emulatore o un dispositivo Android. La l'annotazione deve essere utilizzata su una funzione componibile che non accetta parametri. Per questo motivo, non puoi visualizzare l'anteprima della funzione MessageCard strato Add. Crea invece una seconda funzione denominata PreviewMessageCard, che chiama MessageCard con un parametro appropriato. Aggiungi il parametro Annotazione @Preview prima del giorno @Composable.

// ...
import androidx.compose.ui.tooling.preview.Preview

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

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
mostra anteprima
nascondi anteprima

Ricrea il progetto. L'app in sé non cambia, dato che il nuovo La funzione PreviewMessageCard non viene chiamata da nessuna parte, ma Android Studio aggiunge una finestra di anteprima che puoi espandere facendo clic sull'icona (design/codice). Questa finestra mostra un'anteprima degli elementi UI creati dagli elementi componibili funzioni contrassegnate con l'annotazione @Preview. Per aggiornare delle anteprime in qualsiasi momento, fai clic sul pulsante Aggiorna nella parte superiore della finestra di anteprima.

Anteprima di una funzione componibile 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!")
        }
    }
}
  
mostra anteprima
nascondi anteprima
// ...
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!")
}

  
mostra anteprima
nascondi anteprima
// ...
import androidx.compose.ui.tooling.preview.Preview

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

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
mostra anteprima
nascondi anteprima
Anteprima di una funzione componibile in Android Studio

Lezione 2: Layout

Gli elementi UI sono gerarchici, con elementi contenuti in altri elementi. In Compose, Creare una gerarchia dell'interfaccia utente richiamando funzioni componibili da altre funzioni componibili.

Aggiungi più testi

Finora hai creato la tua prima funzione componibile e l'anteprima. Per scoprire di più su Jetpack Compose di messaggistica, creerai una semplice schermata di messaggistica che contiene un elenco di messaggi può essere espanso con alcune animazioni.

Per iniziare, rendi il messaggio componibile più completo, visualizzando il nome dell'autore e una contenuto del messaggio. Devi prima modificare il parametro componibile per accettare un Message invece di un oggetto String e aggiungine un altro Text componibile all'interno MessageCard componibile. Assicurati di aggiornare l'anteprima .

// ...

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

  
mostra anteprima
nascondi anteprima

Questo codice crea due elementi di testo all'interno della visualizzazione dei contenuti. Tuttavia, poiché non hai fornito informazioni su come disporli, gli elementi di testo vengono disegnati uno sopra l'altro, rendendo illeggibile il testo.

Utilizzo di una colonna

Lo Column ti consente di disporre gli elementi verticalmente. Aggiungi Column a Funzione MessageCard.
Puoi utilizzare Row per disporre gli elementi orizzontalmente Box per sovrapporre gli elementi.

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

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

Aggiungere un elemento all'immagine

Arricchisci la tua scheda del messaggio aggiungendo un'immagine del profilo del mittente. Utilizza la Gestione delle risorse per importare un'immagine dalla tua raccolta fotografica o usa questa. Aggiungi un Row componibile per avere un design ben strutturato e una Image componibile al suo interno.

// ...
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)
        }
  
    }
  
}
  
mostra anteprima
nascondi anteprima

Configurare il layout

Il layout del messaggio ha la struttura corretta, ma gli elementi non sono ben distanziati e l'immagine è troppo grande! Per decorare o configurare un componibile, Compose utilizza dei modificatori. Loro permettono di modificare le dimensioni, il layout e l'aspetto del componibile oppure di aggiungere interazioni di alto livello come rendere cliccabile un elemento. Puoi collegarli per creare elementi componibili più sofisticati. Utilizzerai alcune per migliorare il layout.

// ...
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)
        }
    }
}
  
mostra anteprima
nascondi anteprima
// ...

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

  
mostra anteprima
nascondi anteprima
Anteprima di due elementi componibili di testo sovrapposti
// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
mostra anteprima
nascondi anteprima
// ...
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)
        }
  
    }
  
}
  
mostra anteprima
nascondi anteprima
// ...
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)
        }
    }
}
  
mostra anteprima
nascondi anteprima

Lezione 3: Material Design

Compose è progettato per supportare i principi di Material Design. Molti degli elementi dell'interfaccia utente implementano Material Design pronto all'uso. In questa lezione, imparerai a creare la tua app con Material Design widget.

Utilizzare Material Design

Il design del tuo messaggio ora ha un layout, ma ancora non sembra essere ideale.

Jetpack Compose fornisce un'implementazione di Material Design 3 e dei suoi elementi UI fuori . Migliorerai l'aspetto del nostro MessageCard componibili con lo stile Material Design.

Per iniziare, aggrega la funzione MessageCard con la Tema Material creato nel tuo progetto, ComposeTutorialTheme, e un Surface. Esegui l'operazione sia in @Preview che in Funzione setContent. In questo modo i tuoi componibili per ereditare gli stili definiti nel tema dell'app, garantendo la coerenza in tutta l'app.

Il Material Design si basa su tre pilastri: Color, Typography e Shape. Li aggiungerai uno alla volta.

Nota: il modello Attività di scrittura vuota genera un tema predefinito per il progetto che ti permette di personalizzare MaterialTheme Se hai assegnato al progetto un nome diverso da ComposeTutorial, puoi trovare il tuo tema personalizzato nella Theme.kt file nel ui.theme sottopacchetto.

// ...

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


  
mostra anteprima
nascondi anteprima

Colore

Usa MaterialTheme.colorScheme per applicare stili con i colori del tema aggregato. Puoi utilizzare questi valori del tema ovunque sia necessario un colore. In questo esempio vengono utilizzati colori dinamici per la tematizzazione (definiti dalle preferenze del dispositivo). Puoi impostare dynamicColor su false nel file MaterialTheme.kt per modificare questa impostazione.

Definisci lo stile del titolo e aggiungi un bordo all'immagine.

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

  
mostra anteprima
nascondi anteprima

Tipografia

Gli stili di Material Tipografia sono disponibili in MaterialTheme, devi solo aggiungerli ai componibili 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
           )
       }
   }
}

  
mostra anteprima
nascondi anteprima

Forma

Con Shapepuoi aggiungere gli ultimi ritocchi. Per prima cosa, aggrega testo del corpo del messaggio intorno a Surface componibile. In questo modo, puoi personalizzare la forma e l'elevazione del corpo del messaggio. Al messaggio viene aggiunta anche una spaziatura interna per migliorare il layout.

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

  
mostra anteprima
nascondi anteprima

Attiva tema scuro

Tema scuro (o la modalità notturna) può essere attivata per evitare un display luminoso, soprattutto di notte, o semplicemente per salvare la batteria del dispositivo. Grazie al supporto di Material Design, Jetpack Compose è in grado di affrontare il buio per impostazione predefinita. Utilizzando colori, testo e sfondi di Material Design, si adattano allo sfondo scuro.

Puoi creare più anteprime nel file come funzioni separate o aggiungere più per la stessa funzione.

Aggiungi una nuova annotazione di anteprima e attiva la modalità notturna.

// ...
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!")
      )
    }
   }
}
  
mostra anteprima
nascondi anteprima

Le scelte di colore per i temi chiaro e scuro vengono definite nel file generato dall'IDE Theme.kt.

Finora, hai creato un elemento dell'interfaccia utente per i messaggi che mostra un'immagine e due testi con diversi stili e ha un ottimo aspetto sia con i temi chiari che con i temi scuri.

// ...
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!")
      )
    }
   }
}
  
mostra anteprima
nascondi anteprima
// ...

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


  
mostra anteprima
nascondi anteprima
// ...
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)
       }
   }
}

  
mostra anteprima
nascondi anteprima
// ...

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

  
mostra anteprima
nascondi anteprima
// ...
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
               )
           }
       }
   }
}

  
mostra anteprima
nascondi anteprima
// ...
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!")
      )
    }
   }
}
  
mostra anteprima
nascondi anteprima
Anteprima che mostra i componibili a tema chiaro e scuro.

Lezione 4: Elenchi e animazioni

Elenchi e animazioni sono ovunque nelle app. In questa lezione scoprirai come Compose semplifica la creazione di elenchi e l'aggiunta di animazioni in modo divertente.

Creare un elenco di messaggi

Chattare con un solo messaggio è un po' solitario, quindi cambieremo la conversazione in modo che un solo messaggio. Dovrai creare una funzione Conversation per visualizzare più messaggi. Per questo caso d'uso, utilizza il comando LazyColumn e LazyRow. Questi elementi componibili mostrano solo gli elementi visibili sullo schermo, quindi sono progettati per essere molto efficienti per lunghi elenchi.

In questo snippet di codice, puoi vedere che LazyColumn ha un items figlio. Richiede un List come parametro e la rispettiva funzione lambda riceve un parametro denominato message (potremmo gli abbiamo dato il nome che vogliamo) che è un'istanza di Message. In breve, questo lambda viene chiamato per ogni elemento della List. Copia il set di dati di esempio nel tuo progetto per aiutare il bootstrap della conversazione rapidamente.

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

  
mostra anteprima
nascondi anteprima

Animazione dei messaggi durante l'espansione

La conversazione sta diventando più interessante. È il momento di sperimentare con le animazioni. Aggiungerai possibilità di espandere un messaggio per visualizzarne uno più lungo, animando sia le dimensioni dei contenuti che colore di sfondo. Per archiviare questo stato dell'interfaccia utente locale, devi monitorare se un messaggio è o meno. Per tenere traccia di questo cambiamento di stato, devi usare le funzioni remember e mutableStateOf.

Le funzioni componibili possono archiviare lo stato locale in memoria utilizzando remember e tieni traccia delle modifiche al valore trasmesso a mutableStateOf. I componenti componibili (e i relativi figli) che utilizzano questo stato verrà ridisegnato automaticamente quando il valore viene aggiornato. Questo processo è chiamato ricomposizione.

Utilizzando le API di stato di Compose, come remember e mutableStateOf, qualsiasi modifica allo stato aggiorna automaticamente la UI.

Nota: per utilizzare correttamente il database di Kotlin, devi aggiungere le seguenti importazioni sintassi delle proprietà con delega (la parola chiave by). Alt+Invio o Opzione+Invio le aggiungono per te.
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
                )
            }
        }
    }
}

  
mostra anteprima
nascondi anteprima

Ora puoi modificare lo sfondo dei contenuti dei messaggi in base a: isExpanded quando facciamo clic su un messaggio. Utilizzerai il Modificatore clickable per gestire gli eventi di clic nella componibili. Invece di cambiare semplicemente il colore di sfondo Surface, animerai il colore di sfondo di modificando gradualmente il suo valore MaterialTheme.colorScheme.surface per MaterialTheme.colorScheme.primary e viceversa. Per farlo, userai la funzione animateColorAsState. Infine, userà il tasto di modifica animateContentSize per animare dimensioni del contenitore dei messaggi:

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

  
mostra anteprima
nascondi anteprima
// ...
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)
    }
}

  
mostra anteprima
nascondi anteprima
// ...
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
                )
            }
        }
    }
}

  
mostra anteprima
nascondi anteprima
// ...
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
                )
            }
        }
    }
}

  
mostra anteprima
nascondi anteprima

Passaggi successivi

Congratulazioni, hai terminato il tutorial su Scrivi. Hai creato una schermata della chat semplice che mostra in modo efficiente un elenco di messaggi espandibili e animati contenenti un'immagine e del testo, e il tutto in meno di 100 righe di codice.

Ecco cosa hai imparato finora:

  • Definizione delle funzioni componibili
  • Aggiunta di elementi diversi alla composizione
  • Strutturare il componente dell'interfaccia utente utilizzando i layout componibili
  • Estensione dei componibili mediante modificatori
  • Creazione di un elenco efficiente
  • Monitorare lo stato e modificarlo
  • Aggiunta dell'interazione utente a una creatività componibile
  • Animazione dei messaggi durante l'espansione

Se vuoi approfondire alcuni di questi passaggi, esplora le risorse di seguito.

Passaggi successivi

Configurazione
Ora che hai completato il tutorial su Scrivi, puoi iniziare a creare con Scrivi.
Viale
Dai un'occhiata al nostro percorso selezionato di codelab e video che ti aiuteranno a imparare e a padroneggiare Jetpack Compose.