Carregando imagens com Coil
Carregamento assíncrono de imagens no Compose.
Carregando imagens com Coil é uma aula grátis de Android Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Android Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Android Academy inclui 4 aulas no total.
Por que você precisa de um carregador de imagens
A maioria dos aplicativos modernos exibe imagens da internet: fotos de perfil, imagens de produtos e miniaturas de artigos. Baixar e decodificar essas imagens corretamente é mais difícil do que parece.
É necessário buscar os bytes pela rede em uma thread em segundo plano, decodificá-los em um bitmap, armazená-los em cache para não fazer o download novamente e cancelar a solicitação se o usuário sair daquela área. Fazer tudo isso manualmente é propenso a erros.
Coil (Coroutine Image Loader) cuida de tudo isso para você com uma API pequena e compatível com o Compose. Nesta lição, você carregará sua primeira imagem remota.
Adicionando o Coil ao seu projeto
O Coil é distribuído como uma dependência do Gradle. Para o Jetpack Compose, você deve usar o artefato coil-compose, que fornece o componente AsyncImage.
Adicione-o ao build.gradle.kts do seu módulo. O Coil 3 é a versão principal atual e funciona em várias plataformas; a integração com o Compose é a que usamos aqui.
// build.gradle.kts (module level)
dependencies {
implementation("io.coil-kt.coil3:coil-compose:3.0.4")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.4")
}Permissão de internet
Para baixar imagens de uma URL, seu aplicativo precisa da permissão INTERNET. Esta é uma permissão normal, concedida no momento da instalação, portanto você só precisa declará-la no manifesto. Não há solicitação durante a execução.
Sem ela, todas as solicitações de rede falham com uma exceção de segurança.
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
...
</application>
</manifest>Sua primeira AsyncImage
A maneira mais simples de exibir uma imagem remota no Compose é usar AsyncImage. Informe um model — geralmente uma string de URL — e uma contentDescription, e o Coil fará o restante: busca em segundo plano, decodificação e exibição.
Ele usa automaticamente corrotinas vinculadas à composição, portanto a solicitação é cancelada se o componente sair da tela.
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
@Composable
fun Avatar() {
AsyncImage(
model = "https://example.com/avatar.png",
contentDescription = "User avatar",
modifier = Modifier.size(96.dp)
)
}contentScale: como a imagem se ajusta
Raramente as imagens têm exatamente o mesmo tamanho do espaço reservado pelo layout. ContentScale controla como o bitmap é redimensionado dentro de seus limites.
ContentScale.Croppreenche a caixa e recorta o excesso — ótimo para avatares e miniaturas.ContentScale.Fitmantém a imagem inteira visível, embora possa deixar espaço vazio.ContentScale.FillBoundsestica a imagem para preencher o espaço, o que pode causar distorção.
Crop é a escolha mais comum para espaços de tamanho fixo.
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
@Composable
fun CircleAvatar(url: String) {
AsyncImage(
model = url,
contentDescription = "Avatar",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
)
}Criando uma solicitação com ImageRequest
Passar uma string de URL é o caminho mais rápido. Para ter mais controle, crie um ImageRequest. Isso permite definir opções como transição gradual, cabeçalhos, transformações e chaves de cache.
Você precisa de um Context, que o Compose fornece por meio de LocalContext.current.
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade
@Composable
fun ProductImage(url: String) {
val context = LocalContext.current
val request = ImageRequest.Builder(context)
.data(url)
.crossfade(true)
.build()
AsyncImage(
model = request,
contentDescription = "Product photo"
)
}Transição gradual para carregamentos suaves
Por padrão, a imagem aparece instantaneamente quando termina de carregar, o que pode parecer abrupto. crossfade(true) faz a imagem surgir gradualmente ao longo de uma animação curta.
Você também pode informar uma duração em milissegundos para tornar a transição mais lenta ou mais rápida. Esse pequeno detalhe deixa as listas muito mais refinadas.
import coil3.request.ImageRequest
import coil3.request.crossfade
import android.content.Context
fun smoothRequest(context: Context, url: String) =
ImageRequest.Builder(context)
.data(url)
.crossfade(durationMillis = 300)
.build()Carregando de fontes diferentes
O model de AsyncImage é flexível. O Coil pode carregar vários tipos de fonte, não apenas URLs remotas:
- Uma
StringouUripara arquivos de rede ou locais. - O identificador de um recurso drawable (
R.drawable.logo). - Um
Filedo dispositivo. - Um
Uride conteúdo fornecido pelo seletor de fotos.
Isso significa que o mesmo componente lida perfeitamente com imagens remotas e locais.
import android.net.Uri
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImage
@Composable
fun FlexibleImage(source: Any) {
// source can be a URL String, a Uri, a File, or a resource id
AsyncImage(
model = source,
contentDescription = null
)
}
// Examples:
// FlexibleImage("https://example.com/pic.jpg")
// FlexibleImage(Uri.parse("content://media/external/images/1"))Reagindo ao estado do carregamento
Às vezes, você precisa saber se a imagem está carregando, foi carregada com sucesso ou falhou, para poder exibir uma interface diferente. AsyncImagePainter expõe esse estado, mas a abordagem mais simples é SubcomposeAsyncImage, que permite fornecer conteúdo para cada estado.
Na próxima lição, vamos nos aprofundar nos placeholders; aqui está a estrutura básica de um carregamento que reage ao estado.
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage
@Composable
fun StatefulImage(url: String) {
SubcomposeAsyncImage(
model = url,
contentDescription = "Photo",
loading = { CircularProgressIndicator() }
)
}O cancelamento vem automaticamente
Uma das maiores vantagens do Coil é o cancelamento automático. Como AsyncImage inicia sua solicitação dentro da composição, quando o componente sai da tela — por exemplo, quando uma linha sai da área visível de uma LazyColumn — a solicitação em andamento é cancelada.
Isso economiza largura de banda e CPU e evita trabalho desperdiçado. Você não precisa escrever nenhum código de cancelamento, e é por isso que o Coil funciona tão bem em listas longas.
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
@Composable
fun PhotoFeed(urls: List<String>) {
LazyColumn {
items(urls) { url ->
AsyncImage(
model = url,
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
}
}
}Um cartão de imagem completo
Vamos combinar o que aprendemos: um cartão com uma imagem remota que preenche a parte superior, usa uma transição gradual e é recortada para uma altura fixa. Este é o padrão básico que você reutilizará constantemente.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade
@Composable
fun ImageCard(title: String, imageUrl: String) {
val context = LocalContext.current
Card(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
Column {
AsyncImage(
model = ImageRequest.Builder(context)
.data(imageUrl)
.crossfade(true)
.build(),
contentDescription = title,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxWidth().height(180.dp)
)
Text(text = title, modifier = Modifier.padding(16.dp))
}
}
}Verificação rápida
Qual componente de coil-compose é a maneira mais simples de exibir uma imagem remota por URL no Jetpack Compose?
Recapitulação
Você carregou suas primeiras imagens remotas com o Coil. Principais aprendizados:
- Adicione
coil-composee uma dependência de rede do OkHttp, além da permissãoINTERNET. AsyncImage(model = url, contentDescription = ...)é o caminho mais rápido.- Use
ContentScale.Cropcom um tamanho fixo para avatares e miniaturas. - Crie um
ImageRequestpara usar transição gradual e ter mais controle. - O Coil cancela automaticamente as solicitações em andamento quando os componentes saem da tela.
A seguir: como tornar o carregamento mais agradável com placeholders e estados de erro.
Perguntas Frequentes
A aula “Carregando imagens com Coil” é grátis?
Sim — o texto completo de “Carregando imagens com Coil” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Android Academy, atualize para CoddyKit PRO. O curso de Android Academy inclui 4 aulas no total.
O que vou aprender em “Carregando imagens com Coil”?
Carregamento assíncrono de imagens no Compose. Você pratica Android Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Android Academy?
Nenhuma experiência prévia é necessária. Android Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Carregando imagens com Coil”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Android Academy?
Sim. Cada aula de Android Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Carregando imagens com Coil
- Marcadores e estados de erro
- Cache e desempenho
- Reproduzindo áudio e vídeo