Criar um app simples com elementos de texto de composição

1. Antes de começar

Neste codelab, você usará o Jetpack Compose para criar um app Android simples que mostra uma mensagem de aniversário na tela.

Pré-requisitos

  • Como criar um app no Android Studio.
  • Como executar um app em um emulador ou dispositivo Android.

O que você vai aprender

  • Como escrever funções de composição, como Text, Column e Row.
  • Como mostrar texto no app.
  • Como formatar o texto, mudar o tamanho do texto e da fonte.

O que você vai criar

  • Um app Android que mostra uma mensagem de aniversário em formato de texto. No final, ela vai ficar assim:

1969df37dc980e41.png

Pré-requisitos

  • Um computador com o Android Studio instalado.

2. Assistir ao vídeo de orientações (opcional)

Se você quiser acompanhar a conclusão deste codelab por um dos instrutores do curso, assista ao vídeo abaixo.

Recomendamos abrir o vídeo em tela cheia usando o ícone Símbolo com quatro cantos destacados em um quadrado para indicar o modo de tela cheia. no canto inferior direito da reprodução. Assim, você verá o Android Studio e o código com maior clareza.

Esta etapa é opcional. Você também pode pular o vídeo e começar a seguir as instruções do codelab.

3. Configurar um app Happy Birthday

Nesta tarefa, você vai configurar um projeto no Android Studio com um modelo vazio de atividade de escrita e mudar a mensagem de texto para uma mensagem de aniversário personalizada.

Criar um projeto de atividade vazia de composição

  1. Na caixa de diálogo Welcome to Android Studio, selecione New Project.
  2. Na caixa de diálogo New Project, selecione Empty Compose Activity e clique em Next.
  3. Digite Happy Birthday no campo Name, selecione um nível mínimo de API de 21 (Lollipop) no campo Minimum SDK e clique em Finish.

86730c24681dd2fe.png

  1. Espere o Android Studio criar os arquivos e o projeto.
  2. Clique em fd26b2e3c2870c3.png Run "app"'.

O app vai ficar assim:

282f9427f60fcc5f.png

Quando você cria o app Happy Birthday com o modelo Empty Compose Activity, o Android Studio configura recursos para um app Android básico, incluindo uma mensagem Hello Android! na tela. Neste codelab, você vai aprender como essa mensagem é mostrada, como mudar o texto dela para uma mensagem de aniversário e como adicionar e formatar outras mensagens.

O que é uma interface do usuário (IU)?

A interface do usuário (IU) de um app é o que você vê na tela: texto, imagens, botões e muitos outros tipos de elementos, além de como eles são organizados na tela. Essa é a forma como o app mostra informações ao usuário e como o usuário interage com o app.

Esta imagem contém um botão clicável, uma mensagem de texto e um campo de entrada de texto em que os usuários podem inserir dados.

e5abb8ad9f9ae2a7.png

Botão clicável

fded30871a8e0eca.png

Mensagem de texto

aafb9c476f72d558.png

Campo de entrada de texto

Cada um desses elementos é chamado de componente de IU. Quase tudo o que você vê na tela do app é um elemento da IU (também conhecido como componente da IU). Os elementos podem ser interativos, como um botão clicável ou um campo de entrada editável, ou podem ser imagens decorativas.

Neste codelab, você vai trabalhar com um elemento da IU que mostra um texto chamado de "elemento Text".

4. O que é o Jetpack Compose?

O Jetpack Compose é um kit de ferramentas moderno para a criação de IUs do Android. O Compose simplifica e acelera o desenvolvimento da IU no Android com menos código, ferramentas poderosas e recursos Kotlin intuitivos. Com o Compose, você pode criar a IU definindo um conjunto de funções, chamadas funções de composição, que recebem dados e emitem elementos da IU.

Funções de composição

As funções de composição são o elemento básico de uma IU no Compose. Uma função de composição:

  • descreve uma parte da IU;
  • não retorna nada;
  • recebe uma entrada e gera o que será mostrado na tela;
  • pode emitir vários elementos de IU.

Anotações

Anotações são meios de anexar informações extras ao código. Essas informações ajudam ferramentas como o compilador do Jetpack Compose e outros desenvolvedores a entender o código do app.

Uma anotação é aplicada adicionando o caractere @ como prefixo ao nome dela no início da declaração em questão. Vários elementos de código, como propriedades, funções e classes, podem ser anotados. Mais adiante no curso, você vai aprender sobre classes.

O diagrama a seguir é um exemplo de função com anotação:

1009c41c49d58869.png

O snippet de código a seguir tem exemplos de propriedades anotadas. Você vai usar esses recursos nos próximos codelabs.

// Example code, do not copy it over

@Json
val imgSrcUrl: String

@Volatile
private var INSTANCE: AppDatabase? = null

Anotações com parâmetros

Anotações podem usar parâmetros. Elas fornecem mais informações para as ferramentas que fazem o processamento delas. Veja a seguir alguns exemplos de anotações @preview com e sem parâmetros.

15169d39d744c179.png

Anotação sem parâmetros

992de02d7b5dbfda.png

Plano de fundo da visualização da anotação

fbc159107d248a84.png

Anotação com um título de visualização

É possível transmitir vários parâmetros para a anotação, conforme mostrado aqui.

510f8443a174f972.png

Anotação com título de visualização e IU do sistema (tela do smartphone)

O Jetpack Compose inclui uma ampla variedade de anotações integradas. Você já viu as anotações @Composable e @Preview até o momento. Você vai saber mais sobre as anotações e os usos delas posteriormente no curso.

Exemplo de uma função de composição

A função de composição recebe a anotação @Composable. Todas as funções desse tipo precisam ter essa anotação. Ela informa ao compilador do Compose que essa função se destina a converter dados em IU. Vale lembrar que um compilador é um programa especial que pega o código que você escreveu, analisa linha por linha e converte em algo que o computador pode entender (linguagem de máquina).

O snippet de código abaixo é um exemplo de função simples de composição que recebe dados (o parâmetro de função name) e os usa para renderizar um elemento de texto na tela.

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

Algumas observações sobre a função de composição:

  • As funções de composição podem aceitar parâmetros, que permitem à lógica do app descrever ou modificar a IU. Nesse caso, o elemento da IU aceita uma String para que a mensagem use o nome do usuário.
  • A função não retorna nada. As funções de composição que emitem a IU não precisam retornar nada, porque descrevem o estado desejado da tela, em vez de construir elementos da IU. Em outras palavras, as funções de composição apenas descrevem a IU. Elas não constroem nem criam a IU, então não há nada para retornar.

Observe as funções de composição no código

  1. No Android Studio, abra o arquivo MainActivity.kt.
  2. Role até a função DefaultPreview() e a exclua. Adicione uma nova função de composição, BirthdayCardPreview(), para visualizar a função Greeting() da maneira a seguir. Como prática recomendada, as funções devem sempre ser nomeadas ou renomeadas para descrever a funcionalidade que têm.
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
   BirthdayCardTheme {
       Greeting("Android")
   }
}

As funções de composição podem chamar outras funções desse tipo. Neste snippet de código, a função de visualização está chamando a função de composição Greeting().

Observe que a função anterior também tem outra anotação, @Preview, com um parâmetro antes da anotação @Composable. Você vai saber mais sobre os argumentos transmitidos à anotação Preview mais adiante no curso.

Nomes de funções de composição

A função de composição que não retorna nada e carrega a anotação @Composable PRECISA ser nomeada usando o padrão Pascal Case. Ele se refere a uma convenção de nomenclatura em que a primeira letra de cada palavra em uma palavra composta é maiúscula. A diferença entre o padrão Pascal e o Camel é que todas as palavras no Pascal têm as iniciais maiúsculas. No padrão Camel, a primeira palavra não tem inicial maiúscula.

A função Compose:

  • PRECISA ser um substantivo: DoneButton()
  • NÃO pode ser um verbo ou frase verbal: DrawTextField()
  • NÃO pode ser uma preposição nominal: TextFieldWithLink()
  • NÃO pode ser um adjetivo: Bright()
  • NÃO pode ser um advérbio: Outside()
  • Substantivos PODEM ter adjetivos descritivos como prefixos: RoundIcon()

Essa orientação se aplica sempre, quer a função emita elementos da IU ou não. Para saber mais, consulte Como nomear funções de composição.

Exemplo de código. Não copie

// Do: This function is a descriptive PascalCased noun as a visual UI element
@Composable
fun FancyButton(text: String) {

// Do: This function is a descriptive PascalCased noun as a non-visual element
// with presence in the composition
@Composable
fun BackButtonHandler() {

// Don't: This function is a noun but is not PascalCased!
@Composable
fun fancyButton(text: String) {

// Don't: This function is PascalCased but is not a noun!
@Composable
fun RenderFancyButton(text: String) {

// Don't: This function is neither PascalCased nor a noun!
@Composable
fun drawProfileImage(image: ImageAsset) {

5. Painel Design do Android Studio

O Android Studio permite visualizar as funções de composição no ambiente de desenvolvimento integrado, em vez de instalar o app em um dispositivo ou emulador Android. Como você aprendeu no programa de aprendizagem anterior, é possível ver uma prévia da aparência do app no painel Design do Android Studio.

74e6261fc023772b.png

A função de composição precisa fornecer valores padrão para todos os parâmetros para que seja possível visualizá-la. Por isso, não é possível visualizar a função Greeting() diretamente. Em vez disso, é necessário adicionar outra função, a BirthdayCardPreview(), que chama a função Greeting() com um parâmetro adequado.

@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
   BirthdayCardTheme {
       Greeting("Android")
   }
}

Você vai aprender nos próximos codelabs sobre o parâmetro showBackground na anotação Preview.

Para ver uma prévia:

  1. Crie o código.

A prévia será atualizada automaticamente.

Outra maneira de atualizar a prévia é clicando em fdd133641cfac2b3.png Build & Refresh no painel Design.

5cec5263ba04ea1.png

  1. Na função BirthdayCardPreview(), mude o argumento "Android"" na função Greeting() para seu nome.
fun BirthdayCardPreview() {
   BirthdayCardTheme {
       Greeting("James")
   }
}
  1. Clique em fdd133641cfac2b3.png Build & Refresh no painel Design.

A prévia atualizada será mostrada.

ac506881708bb7fb.png

6. Adicionar um novo elemento de texto

Nesta tarefa, você vai remover a saudação Hello Android! e adicionar uma mensagem de aniversário.

Adicionar uma nova função de composição

  1. No arquivo MainActivity.kt, exclua a definição da função Greeting(). Você vai adicionar sua própria função para mostrar a saudação no codelab mais tarde.
@Composable
fun Greeting(name: String) {
   Text(text = "Hello $name!")
}
  1. O Android Studio destaca a chamada de função Greeting() e, em seguida, passa o cursor sobre essa chamada para identificar o erro.

A função de saudações está destacada e tem um pop-up de erro não resolvido

  1. Exclua a chamada de função Greeting() com os argumentos das funções onCreate() e BirthdayCardPreview(). Seu arquivo MainActivity.kt ficará parecido com este:
class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           BirthdayCardTheme {
               // A surface container using the 'background' color from the theme
               Surface(color = MaterialTheme.colors.background) {
               }
           }
       }
   }
}

@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview(){
   BirthdayCardTheme {
   }
}
  1. Antes da função BirthdayCardPreview(), adicione uma nova função chamada BirthdayGreetingWithText(). Adicione a anotação @Composable antes da função, porque ela será uma função de composição que emitirá um elemento de composição Text.
@Composable
fun BirthdayGreetingWithText() {
}
  1. Adicione um parâmetro message do tipo String à função de composição BirthdayGreetingWithText().
@Composable
fun BirthdayGreetingWithText(message: String) {
}
  1. Na função BirthdayGreetingWithText(), adicione uma função de composição Text() transmitindo a mensagem de texto como um argumento nomeado.
@Composable
fun BirthdayGreetingWithText(message: String) {
    Text(
       text = message
    )
}

A função BirthdayGreetingWithText() mostra texto na IU. Isso é feito chamando a função de composição Text().

Visualizar a função

Nesta tarefa, você vai visualizar a função BirthdayGreetingWithText() no painel Design.

  1. Chame a função BirthdayGreetingWithText() dentro da BirthdayCardPreview().
  2. Transmita um argumento String para a função BirthdayGreetingWithText(), que é uma mensagem de aniversário para seu amigo. Você pode personalizar a mensagem com o nome que quiser, como "Happy Birthday Sam!".
@Preview(showBackground = false)
@Composable
fun BirthdayCardPreview() {
   BirthdayCardTheme {
       BirthdayGreetingWithText( "Happy Birthday Sam!")
   }
}
  1. No painel Design, clique em ea3433426a37f49b.png Build & Refresh e aguarde o término do build para visualizar sua função.

84f2d40e0e0e9289.png

7. Mudar o tamanho da fonte

Você adicionou texto à interface do usuário, mas ele ainda não está com a aparência do app final. Nesta tarefa, você vai aprender a mudar o tamanho e a cor do texto, além de outros atributos que afetam a aparência do elemento de texto. Você também pode testar tamanhos e cores de fonte diferentes.

Pixels escalonáveis

Os pixels escalonáveis (SP, na sigla em inglês) são uma unidade de medida para o tamanho da fonte. Os elementos da IU em apps Android usam duas unidades de medida diferentes: pixels de densidade independente (DP), que será usada depois no layout, e pixels escalonáveis (SP). Por padrão, a unidade SP é do mesmo tamanho que a DP, mas ela é redimensionada com base no tamanho de texto preferencial do usuário nas configurações do smartphone.

  1. No arquivo MainActivity.kt, role até o elemento de composição Text() na função BirthdayGreetingWithText().
  2. Transmita um argumento fontSize à função Text() como um segundo argumento nomeado e o defina como um valor de 36.sp.
Text(
   text = message,
   fontSize = 36.sp
)

O Android Studio destaca o código .sp porque é preciso importar algumas classes ou propriedades para compilar o app.

6b6e60b13e085a13.png

  1. Clique em .sp, que é destacado pelo Android Studio.
  2. Clique no botão Import no pop-up para importar o androidx.compose.ui.unit.sp e usar a propriedade da extensão .sp.

O código de sp tinha um pop-up de referência não resolvido com uma ação de importação.

  1. Role até o topo do arquivo e observe as instruções import, em que você verá uma instrução import androidx.compose.ui.unit.sp, o que significa que o pacote será adicionado ao arquivo pelo Android Studio.

1631e626a2c9e1b8.png

  1. Clique em Build & Refresh no painel Design para ver a prévia atualizada. Observe a mudança no tamanho da fonte na prévia da saudação.

Mostrando a opção "Build & Refresh"

Agora é possível testar diferentes tamanhos de fonte.

8. Adicionar outro elemento de texto

Nas tarefas anteriores, você adicionou uma mensagem de aniversário para seu amigo. Nesta, você vai assinar o cartão com seu nome.

  1. No arquivo MainActivity.kt, role até a função BirthdayGreetingWithText().
  2. Transmita à função um parâmetro from do tipo String para sua assinatura.
fun BirthdayGreetingWithText(message: String, from: String)
  1. Após a mensagem de aniversário Text, adicione outro elemento de composição Text que aceite um argumento text definido como o valor from.
Text(
   text = from
)
  1. Adicione um argumento nomeado fontSize definido como um valor de 24.sp.
Text(
   text = from,
   fontSize = 24.sp
)
  1. Role até a função BirthdayCardPreview().
  2. Adicione outro argumento String para assinar o cartão, como "- from Emma".
BirthdayGreetingWithText( "Happy Birthday Sam!", "- from Emma")
  1. Clique em Build & Refresh no painel Design.
  2. Observe a visualização.

62bc7bf80421de5d.png

Uma função de composição pode emitir vários elementos da IU. No entanto, se você não oferecer orientações sobre como eles devem ser organizados, o Compose poderá organizar os elementos de uma maneira que você não quer. Por exemplo, o código anterior gera dois elementos de texto que se sobrepõem, porque não há orientação sobre como organizar os dois.

Na próxima tarefa, você vai aprender a organizar os elementos de composição em uma linha e uma coluna.

9. Organizar os elementos de texto em uma linha e uma coluna

Hierarquia da IU

A hierarquia da IU é baseada em contenção, o que significa que um componente pode conter um ou mais componentes, e às vezes os termos pai e filho são usados. O contexto é que os elementos pais da IU têm elementos filhos, que por sua vez podem conter elementos filhos. Nesta seção, você vai aprender sobre os elementos de composição Column, Row e Box, que podem atuar como elementos pais da IU.

9270b7e10f954dcb.png

Os três elementos básicos de layout padrão do Compose são Column, Row e Box. Você vai saber mais sobre o elemento de composição Box no próximo codelab.

coluna mostrando três elementos organizados verticalmente e uma linha mostrando três elementos organizados horizontalmente

Column, Row e Box são funções de composição que usam conteúdo de composição como argumentos para que você possa colocar itens dentro desses elementos de layout. Por exemplo, cada elemento filho dentro de um elemento de composição Row é posicionado horizontalmente um ao lado do outro em uma linha.

// Don't copy.
Row {
    Text("First column")
    Text("Second column")
}

Esses elementos de texto são mostrados lado a lado na tela, como visto nesta imagem.

As bordas azuis são apenas para fins demonstrativos e não são mostradas.

20c50a01cc9aa4cb.png

Sintaxe de lambdas finais

No snippet de código anterior, são usadas chaves, em vez de parênteses, na função de composição Row. Isso é chamado de sintaxe de lambdas finais. Você vai aprender sobre lambdas e sintaxe de lambdas finais em detalhes posteriormente no curso. Por enquanto, conheça a sintaxe mais usada do Compose.

O Kotlin oferece uma sintaxe especial para transmitir funções como parâmetros para funções, quando o último parâmetro é uma função.

6373d65802273065.png

Se você quiser transmitir uma função como esse parâmetro, vai poder usar a sintaxe de lambdas finais. Em vez de colocar a função e o nome dela entre parênteses, insira os parênteses depois do nome. Essa é uma situação comum no Compose, então você precisa se familiarizar com a aparência do código.

Por exemplo, o último parâmetro na função de composição Row() é o parâmetro content, uma função que emite os elementos de IU filhos. Suponha que você queira criar uma linha com três elementos de texto. Esse código funcionaria, mas seria muito complicado:

Row(
    content = {
        Text("Some text")
        Text("Some more text")
        Text("Last text")
    }
)

Como o parâmetro content é o último na assinatura da função e o valor dele é transmitido como uma expressão lambda (por enquanto, não tem problema se você não souber o que é lambda, apenas conheça a sintaxe), você pode remover o parâmetro content e os parênteses da seguinte maneira:

Row {
    Text("Some text")
    Text("Some more text")
    Text("Last text")
}

Organizar os elementos de texto em uma linha

Nesta tarefa, você organiza os elementos de texto no seu app em uma linha para evitar sobreposição.

  1. No arquivo MainActivity.kt, role até a função BirthdayGreetingWithText().
  2. Adicione o elemento de composição Row ao redor dos elementos de texto para que ele mostre uma coluna com dois desses elementos.

Agora, a função ficará parecida com este snippet de código:

@Composable
fun BirthdayGreetingWithText(message: String, from: String) {
   Row{
       Text(
           text = message,
           fontSize = 36.sp,
       )
       Text(
           text = from,
           fontSize = 24.sp,
       )
   }
}
  1. Clique em Row no snippet de código destacado.
  2. O Android Studio oferece várias opções de importação para Row.
  3. Clique em Import.

A função da linha é destacada com dois pop-ups. Um deles mostra o erro não resolvido e outro mostra a importação

  1. Selecione o pacote da classe androidx.compose.ui que começa com Row(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.Argument.Horizontal, androidx.....

dfad9fcfae49aa7a.png

  1. Clique em Build & Refresh para atualizar a prévia no painel Design.

A mensagem de aniversário e a assinatura são mostradas lado a lado em uma linha.

A prévia parece muito melhor agora que não há sobreposição. No entanto, não é isso que você quer porque não há espaço suficiente para sua assinatura. Na próxima tarefa, você vai organizar os elementos de texto em uma coluna para resolver esse problema.

Organizar os elementos de texto em uma coluna

Nesta tarefa, você vai mudar a função BirthdayGreetingWithText() para organizar os elementos de texto em uma coluna. Clique em Build & Refresh para atualizar a prévia, que ficará parecida com esta captura de tela:

Mensagem de aniversário e assinatura mostradas uma embaixo da outra em uma coluna.

Agora que você já tentou fazer isso por conta própria, verifique seu código em relação ao código da solução neste snippet:

@Composable
fun BirthdayGreetingWithText(message: String, from: String) {
   Column {
       Text(
           text = message,
           fontSize = 36.sp,
       )
       Text(
           text = from,
           fontSize = 24.sp,
       )
   }
}

Importe este pacote quando solicitado pelo Android Studio:

import androidx.compose.foundation.layout.Column

10. Mostrar no dispositivo

Quando estiver contente com a visualização, é hora de executar o app no seu dispositivo ou emulador.

  1. No arquivo MainActivity.kt, role até a função onCreate().
  2. Chame a função BirthdayGreetingWithText() do bloco Surface.
  3. Transmita a função BirthdayGreetingWithText(), a mensagem de aniversário e a assinatura.

A função onCreate() concluída vai ficar parecida com este snippet de código:

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           BirthdayCardTheme {
               // A surface container that uses the 'background' color from the theme
               Surface(color = MaterialTheme.colors.background) {
                   BirthdayGreetingWithText( "Happy Birthday Sam!", "- from Emma")
               }
           }
       }
   }
}
  1. Crie e execute o app no emulador.

1969df37dc980e41.png

11. Acessar o código da solução

O MainActivity.kt concluído:

package com.example.android.happybirthday

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.example.happybirthday.ui.theme.HappyBirthdayTheme

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           HappyBirthdayTheme {
               // A surface container that uses the 'background' color from the theme
               Surface(color = MaterialTheme.colors.background) {
                   BirthdayGreetingWithText( "Happy Birthday Sam!", "- from Emma")
               }
           }
       }
   }
}

@Composable
fun BirthdayGreetingWithText(message: String, from: String) {
   Column {
       Text(
           text = message,
           fontSize = 36.sp,
       )
       Text(
           text = from,
           fontSize = 24.sp,
       )
   }
}

@Preview(showBackground = false)
@Composable
fun BirthdayCardPreview() {
   HappyBirthdayTheme {
       BirthdayGreetingWithText( "Happy Birthday Sam!", "- from Emma")
   }
}

12. Conclusão

Você criou seu app Happy Birthday.

No próximo codelab, você vai adicionar uma imagem ao app e mudar o alinhamento dos elementos de texto para que fiquem mais bonitos.

Resumo

  • O Jetpack Compose é um kit de ferramentas moderno para criação de IU nativa no Android. Ele simplifica e acelera o desenvolvimento de IUs no Android com menos código, ferramentas poderosas e APIs Kotlin intuitivas.
  • A interface do usuário (IU) de um app é o que você vê na tela: texto, imagens, botões e muitos outros tipos de elementos.
  • Funções de composição são o elemento básico fundamental do Compose. Uma função de composição é uma função que descreve alguma parte da IU.
  • A função de composição recebe a anotação @Composable. Essa anotação informa ao compilador do Compose que essa função se destina a converter dados em IU.
  • Os três elementos básicos de layout padrão do Compose são Column, Row e Box. Essas são funções de composição, ou seja, você pode colocar itens nelas. Por exemplo, cada filho em um Row será colocado horizontalmente um ao lado do outro.

Saiba mais