1. Antes de começar
Desde o início, o Jetpack Compose foi criado com interoperabilidade de visualização, o que significa que ele e o sistema de visualização podem compartilhar recursos e trabalhar lado a lado para mostrar a interface. Essa funcionalidade permite adicionar o Compose ao seu app já existente baseado em visualização. Isso significa que o Compose e as visualizações podem coexistir na base de código até que todo o app esteja totalmente no Compose.
Neste codelab, você vai mudar o item de lista baseado em visualização no app Juice Tracker para usar o Compose. Você pode converter o restante das visualizações do Juice Tracker por conta própria, se quiser.
Se você tem um app que usa uma interface baseada em visualização, talvez não queira reprogramar toda a interface de uma vez. Este codelab ajuda a converter uma única visualização de uma interface baseada em visualização em um elemento do Compose.
Pré-requisitos
- Conhecer a interface baseada em visualização.
- Saber criar um app usando uma interface baseada em visualização.
- Ter experiência com a sintaxe do Kotlin, incluindo lambdas.
- Saber criar um app no Jetpack Compose.
O que você vai aprender
- Como adicionar o Compose a uma tela criada com visualizações do Android.
- Como visualizar um elemento combinável adicionado ao app baseado em visualização.
O que você vai criar
- Você vai converter um item de lista baseado em visualização para o Compose no app Juice Tracker.
2. Visão geral do app inicial
Este codelab usa o código de solução do app Juice Tracker mostrado em Criar um app Android com visualizações como o código inicial. O app inicial já salva dados usando a biblioteca de persistência Room. O usuário pode adicionar informações sobre sucos ao banco de dados do app, como nome, descrição, cor e nota.

Neste codelab, você vai converter o item de lista baseado em visualização para o Compose.

Fazer o download do código inicial para este codelab
Para começar, faça o download do código inicial:
Outra opção é clonar o repositório do GitHub:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git $ cd basic-android-kotlin-compose-training-juice-tracker $ git checkout views
Procure o código no repositório do GitHub do JuiceTracker (link em inglês).
3. Adicionar a biblioteca do Jetpack Compose
Não se esqueça, Compose e Views podem existir juntos em uma determinada tela. Você pode ter alguns elementos da interface no Compose e outros no sistema de visualização. Por exemplo, você pode ter apenas a lista no Compose e o restante da tela no sistema de visualização.
Conclua as etapas a seguir para adicionar a biblioteca do Compose ao app Juice Tracker.
- Abra o Juice Tracker no Android Studio.
- Abra o build.gradle.ktsdo app.
- No bloco buildFeatures, adicione uma flagcompose = true.
buildFeatures {
    //...
    // Enable Jetpack Compose for this module
    compose = true
}
Essa flag permite que o Android Studio funcione com o Compose. Você não realizou essa etapa nos codelabs anteriores, porque o Android Studio gera esse código automaticamente quando você cria um novo projeto de modelo do Compose no Android Studio.
- Abaixo de buildFeatures, adicione o blococomposeOptions.
- No bloco, defina kotlinCompilerExtensionVersioncomo"1.5.1"para definir a versão do compilador Kotlin.
composeOptions {
    kotlinCompilerExtensionVersion = "1.5.1"
}
- Na seção dependencies, adicione dependências do Compose. Você precisa das dependências a seguir para adicionar o Compose a um app baseado em visualização. Essas dependências ajudam a integrar o Compose à atividade, adicionar a biblioteca de componentes de design do Compose, oferecer suporte aos temas do Jetpack e fornecer ferramentas para melhorar o suporte ao ambiente de desenvolvimento integrado.
dependencies {
    implementation(platform("androidx.compose:compose-bom:2023.06.01"))
    // other dependencies 
    // Compose
    implementation("androidx.activity:activity-compose:1.7.2")
    implementation("androidx.compose.material3:material3")
    implementation("com.google.accompanist:accompanist-themeadapter-material3:0.28.0")
    debugImplementation("androidx.compose.ui:ui-tooling")
}
Adicionar ComposeView
Uma ComposeView é uma visualização do Android que pode hospedar conteúdo da interface do Jetpack Compose. Use setContent para fornecer a função combinável do conteúdo para a visualização.
- Abra o layout/list_item.xmle confira a prévia na guia Split.
Ao final deste codelab, você vai substituir essa visualização por um elemento combinável.

- No JuiceListAdapter.kt, removaListItemBindingde todos os lugares. Na classeJuiceListViewHolder, substituabinding.rootporcomposeView.
import androidx.compose.ui.platform.ComposeView
class JuiceListViewHolder(
    private val onEdit: (Juice) -> Unit,
    private val onDelete: (Juice) -> Unit
): RecyclerView.ViewHolder(composeView) 
- Na pasta onCreateViewHolder(), atualize a funçãoreturn()para que ela fique como este código:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JuiceListViewHolder {
   return JuiceListViewHolder(
       ComposeView(parent.context),
       onEdit,
       onDelete
   )
}
- Na classe JuiceListViewHolder, exclua todas as variáveisprivatee remova todo o código da funçãobind(). A classeJuiceListViewHolderagora terá esta aparência:
class JuiceListViewHolder(
    private val onEdit: (Juice) -> Unit,
    private val onDelete: (Juice) -> Unit
) : RecyclerView.ViewHolder(composeView) {
   fun bind(juice: Juice) {
   }
}
- Agora, é possível excluir as importações com.example.juicetracker.databinding.ListItemBindingeandroid.view.LayoutInflater.
// Delete
import com.example.juicetracker.databinding.ListItemBinding
import android.view.LayoutInflater
- Exclua o arquivo layout/list_item.xml.
- Selecione OK na caixa de diálogo Delete.

4. Adicionar função combinável
Agora, crie um elemento combinável que emita o item de lista. A função combinável usa Juice e duas funções de callback para editar e excluir o item de lista.
- No JuiceListAdapter.kt, após a definição da classeJuiceListAdapter, crie uma função combinável chamadaListItem().
- Faça com que a função ListItem()aceite o objetoJuicee um callback lambda para exclusão.
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun ListItem(
    input: Juice,
    onDelete: (Juice) -> Unit,
    modifier: Modifier = Modifier
) {
}
Observe a prévia do item de lista que você quer criar. Ela mostra um ícone e detalhes do suco, além de um botão de exclusão. Você vai implementar esses componentes em breve.

Criar o elemento combinável do ícone de suco
- No JuiceListAdapter.kt, depois do elemento combinávelListItem(), crie outra função combinável chamadaJuiceIcon()que usa umacolore umModifier.
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
}
- Na função JuiceIcon(), adicione variáveis para acolore a descrição do conteúdo, conforme mostrado no seguinte código:
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
   val colorLabelMap = JuiceColor.values().associateBy { stringResource(it.label) }
   val selectedColor = colorLabelMap[color]?.let { Color(it.color) }
   val juiceIconContentDescription = stringResource(R.string.juice_color, color)
}
Usando as variáveis colorLabelMap e selectedColor, você vai recuperar o recurso de cores associado à seleção do usuário.
- Adicione um layout Boxpara mostrar dois íconesic_juice_coloreic_juice_clear, um sobre o outro. O íconeic_juice_colortem uma tonalidade e está alinhado ao centro.
import androidx.compose.foundation.layout.Box
Box(
   modifier.semantics {
       contentDescription = juiceIconContentDescription
   }
) {
   Icon(
       painter = painterResource(R.drawable.ic_juice_color),
       contentDescription = null,
       tint = selectedColor ?: Color.Red,
       modifier = Modifier.align(Alignment.Center)
   )
   Icon(painter = painterResource(R.drawable.ic_juice_clear), contentDescription = null)
}
Como você já conhece a implementação de um elemento combinável, os detalhes sobre essa etapa não são fornecidos.
- Adicione uma função para visualizar JuiceIcon(). Transmita a cor comoYellow.
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
fun PreviewJuiceIcon() {
    JuiceIcon("Yellow")
}

Criar elementos combináveis de detalhes do suco
No JuiceListAdapter.kt, é necessário adicionar outra função combinável para mostrar os detalhes do suco. Você também precisa de um layout de coluna para mostrar dois elementos combináveis Text para o nome e a descrição, além de um indicador de nota. Para isso, siga estas etapas:
- Adicione uma função combinável com o nome JuiceDetails(), que usa um objetoJuicee umModifier, além de um elemento combinável de texto para o nome e outro para a descrição do suco, conforme mostrado no código abaixo:
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.ui.text.font.FontWeight
@Composable
fun JuiceDetails(juice: Juice, modifier: Modifier = Modifier) {
   Column(modifier, verticalArrangement = Arrangement.Top) {
       Text(
           text = juice.name,
           style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.Bold),
       )
       Text(juice.description)
       RatingDisplay(rating = juice.rating, modifier = Modifier.padding(top = 8.dp))
   }
}
- Para resolver o erro de referência, crie uma função combinável chamada RatingDisplay().

No sistema de visualização, você tem uma RatingBar para mostrar a barra de nota a seguir. Como o Compose não tem um elemento combinável da barra de nota, é necessário implementar esse elemento do zero.
- Defina a função RatingDisplay()para mostrar as estrelas de acordo com a nota. Essa função combinável mostra o número de estrelas com base na classificação.

import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource
@Composable
fun RatingDisplay(rating: Int, modifier: Modifier = Modifier) {
   val displayDescription = pluralStringResource(R.plurals.number_of_stars, count = rating)
   Row(
       // Content description is added here to support accessibility
       modifier.semantics {
           contentDescription = displayDescription
       }
   ) {
       repeat(rating) {
           // Star [contentDescription] is null as the image is for illustrative purpose
           Image(
               modifier = Modifier.size(32.dp),
               painter = painterResource(R.drawable.star),
               contentDescription = null
           )
       }
   }
}
Para criar o drawable de estrela no Compose, é necessário criar o recurso de vetor de estrelas.
- No painel Project, clique com o botão direito do mouse em drawable > New > Vector Asset.

- Na caixa de diálogo do Asset Studio, procure um ícone de estrela. Selecione o ícone de estrela preenchida.


- Mude o valor de cor da estrela para 625B71.

- Clique em Next > Finish.
- Um drawable aparece na pasta res/drawable.

- Adicione um elemento combinável de prévia para JuiceDetails.
@Preview
@Composable
fun PreviewJuiceDetails() {
    JuiceDetails(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4))
}

Criar um elemento combinável do botão de exclusão
- No JuiceListAdapter.kt, adicione outra função combinável chamadaDeleteButton(), que usa uma função de callback de lambda e um modificador.
- Defina a lambda como o argumento onClicke transmita oIcon()conforme mostrado no seguinte código:
import androidx.compose.ui.res.painterResource
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@Composable
fun DeleteButton(onDelete: () -> Unit, modifier: Modifier = Modifier) {
    IconButton(
        onClick = { onDelete() },
        modifier = modifier
    ) {
        Icon(
            painter = painterResource(R.drawable.ic_delete),
            contentDescription = stringResource(R.string.delete)
        )
    }
}
- Adicione uma função de prévia para o botão de exclusão.
@Preview
@Composable
fun PreviewDeleteIcon() {
    DeleteButton({})
}

5. Implementar a função ListItem
Agora que você tem todos os elementos combináveis necessários para mostrar o item de lista, eles podem ser organizados em um layout. Observe a função ListItem() definida na etapa anterior.
@Composable
fun ListItem(
   input: Juice,
   onEdit: (Juice) -> Unit,
   onDelete: (Juice) -> Unit,
   modifier: Modifier = Modifier
) {
}
No JuiceListAdapter.kt, conclua as etapas a seguir para implementar a função ListItem().
- Adicione um layout Rowdentro do lambdaMdc3Theme {}.
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import com.google.accompanist.themeadapter.material3.Mdc3Theme
Mdc3Theme {
   Row(
       modifier = modifier,
       horizontalArrangement = Arrangement.SpaceBetween
   ) {
   }
}
- No lambda Row, chame os três elementos combináveis (JuiceIcon,JuiceDetailseDeleteButton) que você criou como elementos filhos.
JuiceIcon(input.color)
JuiceDetails(input, Modifier.weight(1f))
DeleteButton({})
A transmissão do Modifier.weight(1f) para o elemento combinável JuiceDetails() garante que os detalhes do suco ocupem o espaço horizontal restante depois de medir os elementos filhos sem peso.
- Transmita a lambda onDelete(input)e o modificador com alinhamento superior como parâmetros para o elemento combinávelDeleteButton.
DeleteButton(
   onDelete = {
       onDelete(input)
   },
   modifier = Modifier.align(Alignment.Top)
)
- Crie uma função de prévia para o elemento combinável ListItem.
@Preview
@Composable
fun PreviewListItem() {
   ListItem(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4), {})
}

- Vincule o elemento combinável ListItemao armazenador de visualização. ChameonEdit(input)na função lambdaclickable()para abrir a caixa de diálogo de edição quando houver um clique no item da lista.
Na classe JuiceListViewHolder, dentro da função bind(), você precisa hospedar o elemento combinável. Use a ComposeView, que é uma visualização do Android que pode hospedar conteúdo da interface do Compose utilizando o método setContent.
fun bind(input: Juice) {
    composeView.setContent {
        ListItem(
            input,
            onDelete,
            modifier = Modifier
                .fillMaxWidth()
                .clickable {
                    onEdit(input)
                }
                .padding(vertical = 8.dp, horizontal = 16.dp),
       )
   }
}
- Execute o app e adicione seu suco favorito. Observe o item de lista do Compose.
 .
.            
Parabéns! Você acabou de criar seu primeiro app de interoperabilidade do Compose que usa elementos do Compose em um app baseado em visualização.
6. Acessar o código da solução
Para baixar o código do codelab concluído, use estes comandos git:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git $ cd basic-android-kotlin-compose-training-juice-tracker $ git checkout views-with-compose
Se preferir, você pode baixar o repositório como um arquivo ZIP, descompactar e abrir no Android Studio.
Se você quiser conferir o código da solução, acesse o GitHub (link em inglês).
7. Saiba mais
Documentação do desenvolvedor Android
- Ferramentas para Compose | Jetpack Compose | Desenvolvedores Android
- APIs de interoperabilidade | Jetpack Compose | Desenvolvedores Android
- Estratégia de migração | Jetpack Compose | Desenvolvedores Android
Codelab [intermediário]
