1. Antes de começar
Neste codelab, você vai 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 combináveis, como
Text
,Column
eRow
. - Como mostrar texto no app em um layout.
- Como formatar o texto, por exemplo, mudando o tamanho dele.
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:
O que é necessário
- 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.
É recomendável abrir o vídeo em tela cheia. No player de vídeo, clique no ícone Tela cheia para conferir o Android Studio e o código com mais clareza.
Esta etapa é opcional. Você 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 Empty Compose Activity e mudar a mensagem de texto para uma mensagem de aniversário personalizada.
Criar um projeto de atividade vazia de composição
- Na caixa de diálogo Welcome to Android Studio, selecione New Project.
- Na caixa de diálogo New Project, selecione Empty Compose Activity e clique em Next.
- Digite
Happy Birthday
no campo Name, selecione um nível mínimo de API de 24 (Nougat) no campo Minimum SDK e clique em Finish.
- Espere o Android Studio criar os arquivos e o projeto.
- Clique em
Run 'app'.
O app vai ficar assim:
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 é mostrado 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.
Botão clicável
Mensagem de texto
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.
Nos apps abaixo, tente encontrar o máximo possível de componentes de interface.
Neste codelab, você vai trabalhar com um elemento da interface que mostra texto, conhecido como "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 abaixo é um exemplo de função com anotação:
O snippet de código abaixo 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. Confira abaixo alguns exemplos de anotação @Preview
com e sem parâmetros.
Anotação sem parâmetros
Plano de fundo da visualização da anotação
Anotação com um título de visualização
É possível transmitir vários parâmetros para a anotação, conforme mostrado aqui.
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á aprendeu sobre as anotações @Composable
e @Preview
até agora. Vamos falar mais sobre as anotações e os usos delas mais adiante no curso.
Exemplo de uma função combinável
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
- No Android Studio, abra o arquivo
MainActivity.kt
. - Role até a função
DefaultPreview()
e a exclua. Adicione uma nova função de composição,BirthdayCardPreview()
, para visualizar a funçãoGreeting()
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() {
HappyBirthdayTheme {
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 conferir uma prévia da aparência do app no painel Design do Android Studio.
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() {
HappyBirthdayTheme {
Greeting("Android")
}
}
Para conferir uma prévia:
- Crie o código.
A prévia será atualizada automaticamente.
Outra maneira de atualizar a prévia é clicando em Build & Refresh no painel Design.
- Na função
BirthdayCardPreview()
, mude o argumento"Android"
na funçãoGreeting()
para seu nome.
fun BirthdayCardPreview() {
HappyBirthdayTheme {
Greeting("James")
}
}
- Clique em
Build & Refresh no painel Design.
A prévia atualizada vai aparecer.
6. Adicionar um novo elemento de texto
Nesta tarefa, você vai remover a saudação Hello $name!
e adicionar uma mensagem de aniversário.
Adicionar uma nova função de composição
- No arquivo
MainActivity.kt
, exclua a definição da funçãoGreeting()
. 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!")
}
- Passe o cursor sobre a função
Greeting()
. O Android Studio destaca a chamada de funçãoGreeting()
e, em seguida, passa o cursor sobre essa chamada para identificar o erro.
- Exclua a chamada de função
Greeting()
com os argumentos das funçõesonCreate()
eBirthdayCardPreview()
. Seu arquivoMainActivity.kt
ficará parecido com este:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview(){
HappyBirthdayTheme {
}
}
- Antes da função
BirthdayCardPreview()
, adicione uma nova função chamadaBirthdayGreetingWithText()
. Adicione a anotação@Composable
antes da função, porque ela será uma função combinável que emitirá um elemento combinávelText
.
@Composable
fun BirthdayGreetingWithText() {
}
- É uma prática recomendada que a função combinável aceite um parâmetro
Modifier
e transmita essemodifier
ao primeiro filho que emite a interface. Você vai saber mais sobre oModifier
e elementos filhos nas próximas tarefas e codelabs. Por enquanto, adicione um parâmetroModifier
à funçãoBirthdayGreetingWithText()
.
@Composable
fun BirthdayGreetingWithText(modifier: Modifier = Modifier) {
}
- Adicione um parâmetro
message
do tipoString
à função combinávelBirthdayGreetingWithText()
.
@Composable
fun BirthdayGreetingWithText(message: String, modifier: Modifier = Modifier) {
}
- Na função
BirthdayGreetingWithText()
, adicione uma função de composiçãoText
transmitindo a mensagem de texto como um argumento nomeado.
@Composable
fun BirthdayGreetingWithText(message: String, modifier: Modifier = Modifier) {
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.
- Chame a função
BirthdayGreetingWithText()
dentro daBirthdayCardPreview()
. - Transmita um argumento
String
para a funçãoBirthdayGreetingWithText()
, 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 = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
BirthdayGreetingWithText(message = "Happy Birthday Sam!")
}
}
- No painel Design, clique em
Build & Refresh e aguarde o término do build para visualizar sua função.
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.
- No arquivo
MainActivity.kt
, role até o elemento de composiçãoText()
na funçãoBirthdayGreetingWithText()
. - Transmita um argumento
fontSize
à funçãoText()
como um segundo argumento nomeado e o defina como um valor de36.
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.
- Clique em
.sp
, que é destacado pelo Android Studio. - Clique no botão Import no pop-up para importar o
androidx.compose.ui.unit.sp
e usar a propriedade da extensão.sp
.
- Role até o topo do arquivo e observe as instruções
import
, em que você encontrará uma instruçãoimport androidx.compose.ui.unit.sp
, o que significa que o pacote será adicionado ao arquivo pelo Android Studio.
- 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.
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.
- No arquivo
MainActivity.kt
, role até a funçãoBirthdayGreetingWithText()
. - Transmita à função um parâmetro
from
do tipoString
para sua assinatura.
fun BirthdayGreetingWithText(message: String, from: String, modifier: Modifier = Modifier)
- Após a mensagem de aniversário
Text
, adicione outro elemento de composiçãoText
que aceite um argumentotext
definido como o valorfrom
.
Text(
text = from
)
- Adicione um argumento nomeado
fontSize
definido como um valor de24.sp
.
Text(
text = from,
fontSize = 24.sp
)
- Role até a função
BirthdayCardPreview()
. - Adicione outro argumento
String
para assinar o cartão, como"- from Emma"
.
BirthdayGreetingWithText(message = "Happy Birthday Sam!", from ="- from Emma")
- Clique em Build & Refresh no painel Design.
- Observe a visualização.
Uma função combinável pode emitir vários elementos da interface. 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 interface têm elementos filhos, que por sua vez podem conter outros elementos filhos. Nesta seção, você vai aprender sobre os elementos combináveis Column
, Row
e Box
, que podem atuar como elementos pais da interface.
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 combinável Box
no próximo codelab.
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.
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 mais adiante no curso. Por enquanto, conheça esta sintaxe mais usada do Compose.
O Kotlin oferece uma sintaxe especial para transmitir funções como parâmetros para outras funções, quando o último parâmetro também é uma função.
Se você quiser transmitir uma função como esse parâmetro, vai poder usar a sintaxe de lambdas finais. Em vez de colocar o corpo da função junto com o nome da função entre parênteses({}
), coloque os parênteses com o corpo da função após o nome da função. 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")
}
)
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 é uma lambda, apenas conheça a sintaxe. É possível remover o parâmetro content
e os parênteses desta 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.
- No arquivo
MainActivity.kt
, role até a funçãoBirthdayGreetingWithText()
. - 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, modifier: Modifier = Modifier) {
Row{
Text(
text = message,
fontSize = 36.sp,
)
Text(
text = from,
fontSize = 24.sp,
)
}
}
- Clique em
Row
no snippet de código destacado. - O Android Studio oferece várias opções de importação para
Row
. - Clique em Import.
- No pacote
androidx.compose.foundation.layout
, selecione a função que começa comRow(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.Argument.Horizontal, androidx
....
.
- Clique em Build & Refresh para atualizar a prévia no painel Design.
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, é sua vez de mudar a função BirthdayGreetingWithText()
para organizar os elementos de texto em uma coluna. Quando terminar, clique em Build & Refresh para atualizar a prévia, que ficará parecida com esta captura de tela:
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, modifier: Modifier = Modifier) {
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
- Não se esqueça que você precisa transmitir o parâmetro modificador aos elementos filhos dos elementos combináveis. Isso significa que você precisa transmitir o parâmetro ao elemento combinável
Column
.
@Composable
fun BirthdayGreetingWithText(message: String, from: String, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
Text(
text = message,
fontSize = 36.sp,
)
Text(
text = from,
fontSize = 24.sp,
)
}
}
10. Mostrar no dispositivo
Quando estiver contente com a visualização, é hora de executar o app no seu dispositivo ou emulador.
- No arquivo
MainActivity.kt
, role até a funçãoonCreate()
. - Chame a função
BirthdayGreetingWithText()
do blocoSurface
. - 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 {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
BirthdayGreetingWithText( message = "Happy Birthday Sam!", from = "- from Emma")
}
}
}
}
}
- Crie e execute o app no emulador.
11. Acessar o código da solução
O MainActivity.kt
concluído:
package com.example.happybirthday
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
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 using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
BirthdayGreetingWithText( message = "Happy Birthday Sam!", from = "- from Emma")
}
}
}
}
}
@Composable
fun BirthdayGreetingWithText(message: String, from: String, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
Text(
text = message,
fontSize = 36.sp,
)
Text(
text = from,
fontSize = 24.sp,
)
}
}
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
BirthdayGreetingWithText(message = "Happy Birthday Sam!", from ="- 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,
eBox
. Essas são funções de composição, ou seja, você pode colocar itens nelas. Por exemplo, cada filho em umRow
será colocado horizontalmente um ao lado do outro.