DEV Community

Cover image for Como desenhar telas no Jetpack Compose
Alex Felipe
Alex Felipe

Posted on

Como desenhar telas no Jetpack Compose

O Jetpack Compose é uma ferramenta bastante poderosa para criar telas nativas no Android.

Embora a ideia da ferramenta seja facilitar a implementação de telas, se não compreendermos a finalidade de cada componente, não será uma tarefa fácil!

Considerando esses detalhes, vamos entender como devemos pensar no momento que criamos uma tela.

Amostra de implementação

Como demonstração, vamos utilizar a seguinte tela:

Preview de um card com bordas arredondas, imagem no topo preenchendo toda a largura do card, abaixo em layout de coluna, contém o título, subtítulo, ícone de favorito e botão com mensagem 'ler agora'. ícone de favorito e botão estão em layout de linha, sendo que o ícone está na extrema esquerda e botão na extrema direita

Agora que conhecemos a tela, precisamos compreender a lógica de analise antes de começar a implementação.

Identificando os elementos visuais

Como primeiro passo, podemos começar a analise identificando os elementos visuais. De uma forma genérica, temos:

  • imagem de capa
  • texto de título
  • texto de subtítulo
  • ícone de favorito
  • botão de leitura

Analisando o layout da tela

Então, precisamos analisar o layout geral. Observe que todos os elementos estão organizados em coluna, sendo que o ícone e botão, estão em linha!

Com apenas essa analise, podemos implementar o primeiro código da tela com composable de layout:

Column {
    AsyncImage(
        "https://picsum.photos/1920/1080",
        contentDescription = "Imagem de capa"
    )
    Text(text = "Título")
    Text(text = "Subtitulo")
    Row {
        Icon(
            Icons.Outlined.FavoriteBorder,
            contentDescription = "ícone de favorito"
        )
        Button(onClick = { /*TODO*/ }) {
            Text(text = "Ler agora")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

App em execução apresentando a tela com imagem, título, subtítulo, ícone e botão no layout de coluna. Ícone e botão no layout em linha

Embora o design não esteja fiel a amostra, já temos tudo que precisamos para seguir com o próximo passo, personalizar os componentes da tela.

Fazendo uma analogia ao front-end na web, basicamente, adicionamos o HTML para estruturar a página!

Personalizando a tela com o Modifier

Assim como há os composables para estruturar a tela, temos o Modifier como entidade responsável em personalizar, dar comportamentos e reagir a eventos dos composables. Sendo assim, vamos utilizá-lo para modificar os composables

Seguindo a analogia com front-end, o Modifier seria um CSS do Jetpack Compose.

Ajustando o container principal

Podemos começar a personalização por qualquer componente, mas, geralmente tendo seguir uma estratégia, começar pelo componente mais externo até o mais interno, portanto, vamos começar com o Column mais externo:

Column(
    Modifier
        .padding(8.dp)
        .fillMaxWidth()
        .border(
            0.5.dp,
            Color.Gray.copy(alpha = 0.5f),
            RoundedCornerShape(20.dp)
        )
) {
    ...
}
Enter fullscreen mode Exit fullscreen mode

App em execução apresentado o card com espaçamento entre as extremidades da tela e bordas arredondadas

Todo composable recebe como primeiro parâmetro opcional um Modifier, pois existe o Modifier padrão. Para mais detalhes, você pode verificar nesta thread sobre modificadores..

Note que agora já temos um destaque ao container que representa o card, exibindo um espaçamento e bordas arredondadas.

Personalizando a imagem de capa

Por mais que o container do card foi ajustado corretamente, a imagem ainda apresenta o aspecto quadrado e ultrapassa as extremidades do container principal, para resolver isso, podemos aplicar o modificador na imagem também:

Column(
    ...
) {
    AsyncImage(
        "https://picsum.photos/1920/1080",
        contentDescription = "Imagem de capa",
        Modifier
            .height(100.dp)
            .clip(
                RoundedCornerShape(
                    topStart = 20.dp,
                    topEnd = 20.dp
                )
            ),
        contentScale = ContentScale.Crop,
        placeholder = ColorPainter(Color.Gray)
    )
    ...
}
Enter fullscreen mode Exit fullscreen mode

Card e imagem de capa com as bordas arredondadas

Note que além do modificador, utilizei alguns parâmetros próprios do AsyncImage:

  • contentScale: o container da imagem vai ter uma altura fixa, na escala padrão, ela fica distorcida ao tentar exibir todo conteúdo da imagem. Aplicando o corte com o ContentScale.Crop, apresenta a imagem cortada no espaço disponível.
  • placeholder: apresenta conteúdo no preview e durante o carregamento da imagem via internet, nesse caso, um fundo cinza

Agora que a imagem de capa foi ajustada, vamos para os textos.

Modificando os textos

Podemos modificar os textos da seguinte maneira:

Column(
    ...
) {
    ...
    Text(
        text = "Título",
        Modifier.padding(
            start = 16.dp,
            top = 16.dp,
            end = 16.dp,
            bottom = 8.dp
        ),
        fontSize = 24.sp
    )
    Text(
        text = "Subtitulo",
        Modifier.padding(
            start = 16.dp,
            end = 16.dp,
            bottom = 16.dp
        ),
        fontSize =
        14.sp
    )
    ...
}

}
Enter fullscreen mode Exit fullscreen mode

Card aplicando espaçamento e tamanho de fonte no título e subtitulo

Mesmo que os textos foram modificados como esperado, é válido notar que tivemos que aplicar diversos números para o espaçamento...

Em casos como esses, podemos utilizar composables de layout para simplificar a implementação, como por exemplo, envolver os Texts em coluna e modificar o espaçamento da coluna e ajustar o arranjo vertical:

Column(
    ...
) {
    ...
    Column(
        Modifier.padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Text(
            text = "Título",
            fontSize = 24.sp
        )
        Text(
            text = "Subtitulo",
            fontSize = 14.sp
        )
    }
    ...
}
Enter fullscreen mode Exit fullscreen mode

Tanto o Row como o Column, possuem parâmetros extras para manipular os seus filhos, ou seja, os composables que são organizados por eles.

Com esse ajuste, temos o mesmo resultado de antes! Mais simples, concorda? Por fim, precisamos apenas ajustar a linha final.

Ajustando o ícone e botão em linha

O ajuste da linha é bastante similar ao que fizemos na coluna anterior:

Column(
    ...
) {
    ...
    Row(
        Modifier
            .padding(16.dp)
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceBetween,
        verticalAlignment = Alignment.CenterVertically
    ) {
        Icon(
            Icons.Outlined.FavoriteBorder,
            contentDescription = "ícone de favorito"
        )
        Button(onClick = { /*TODO*/ }) {
            Text(text = "Ler agora")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Card com o ícone de favorito e botão para ler em linha alinhados nas extremidades da tela, sendo o ícone a esquerda e botão direito na direita. Também, com espaçamento aplicado

A grande diferença fica na aplicação da largura com o fillMaxWidth() em conjunto do arranjo e alinhamento.

Essa técnica é utilizada para que seja possível aplicar o Arrangement.SpaceBetween que organiza os filhos nas extremidades, já o alinhamento, centraliza os filhos verticalmente.

Conclusão

Em um primeiro momento, a implementação de telas no Jetpack Compose pode parecer complexa, porém, vimos que podemos aplicar algumas técnicas para facilitar a escrita de código.

Considerando o que vimos, temos:

  • identificação dos elementos visuais
  • analise do layout
  • aplicação de modificadores em cada componente
  • ordem de modificação para facilitar

O que achou de criar telas no Jetpack Compose? Você já usa essas técnicas ou tem outros macetes para facilitar a implementação?

Top comments (1)

Collapse
 
rodrocksoftware profile image
Rodrigo Rodrock

Parabéns pelo conteúdo de alta qualidade Felipe. Sucesso!