1. Antes de começar
Neste codelab, você vai adicionar imagens de dados ao seu app Android Dice Roller. Antes disso, você precisa concluir o codelab anterior sobre como criar a base do app Dice Roller.
Em vez de exibir os números do dado em uma TextView
, o app vai mostrar as imagens correspondentes aos números dos lados que foram tirados. Isso vai resultar em uma experiência muito mais visual e aprimorada para o app.
Você vai receber um link para fazer o download das imagens, que serão adicionadas como recursos ao seu app. Para escrever o código de qual imagem do dado será escolhida, você vai usar uma instrução when
em Kotlin.
Pré-requisitos
- Conclusão do codelab "Criar um app Dice Roller interativo".
- Sabe escrever instruções de fluxo de controle (instruções
if / else
,when
). - Sabe atualizar a IU do app com base na entrada do usuário (modificando o arquivo
MainActivity.kt
). - Sabe adicionar um listener de clique a um
Button.
- Sabe adicionar recursos de imagem a um app Android.
O que você vai aprender
- Como atualizar uma
ImageView
enquanto o app está em execução. - Como personalizar o comportamento do app com base em diferentes condições (usando uma instrução
when
).
O que você vai criar
- O app Android Dice Roller com um
Button
para jogar um dado e atualizar a imagem na tela.
O que é necessário
- Um computador com o Android Studio instalado.
- Conexão de Internet para fazer o download das imagens de dados.
2. Atualizar o layout do app
Nesta tarefa, você vai substituir a TextView
no layout por uma ImageView
que mostra uma imagem do valor resultante do dado.
Abrir o app Dice Roller
- Abra e execute o app Dice Roller do codelab anterior no Android Studio. É possível usar o código de solução ou o código criado por você.
O app vai ficar assim:
- Abra
activity_main.xml
(app > res > layout > activity_main.xml). O Layout Editor vai abrir.
Excluir a TextView
- No Layout Editor, selecione a
TextView
na seção Component Tree.
- Clique com o botão direito e escolha Delete ou pressione a tecla
Delete
. - Ignore o aviso no
Button
por enquanto. Isso vai ser corrigido na próxima etapa.
Adicionar uma ImageView ao layout
- Arraste uma
ImageView
da Palette para a visualização Design, acima doButton
.
- Na caixa de diálogo Pick a Resource, selecione avatars em Sample data. Essa é a imagem temporária que será usada até que as imagens de dados sejam adicionadas na próxima tarefa.
- Pressione OK. A visualização Design do app vai ficar assim.
- Em Component Tree, você vai observar dois erros. O
Button
não tem uma restrição vertical, e aImageView
não tem restrição vertical nem horizontal.
O Button
não tem uma restrição vertical porque você removeu a TextView
abaixo da qual ele estava posicionado originalmente. Agora você precisa posicionar a ImageView
e o Button
abaixo dela.
Posicionar a ImageView e o Button
Você precisa centralizar verticalmente a ImageView
na tela, independentemente do local em que o Button
está localizado.
- Adicione restrições horizontais à
ImageView
. Conecte o lado esquerdo daImageView
à borda esquerda doConstraintLayout
pai. - Conecte o lado direito da
ImageView
à borda direita do pai. Isso vai centralizar aImageView
horizontalmente dentro do layout pai.
- Adicione uma restrição vertical à
ImageView
, conectando a parte de cima daImageView
à parte de cima do pai. AImageView
vai deslizar para o topo doConstraintLayout
.
- Adicione uma restrição vertical ao
Button
, conectando a parte de cima doButton
à parte de baixo daImageView
. OButton
vai deslizar até ficar abaixo daImageView
.
- Agora, selecione a
ImageView
novamente e adicione uma restrição vertical que conecta a parte de baixo daImageView
à parte de baixo do layout pai. Isso centraliza aImageView
verticalmente noConstraintLayout
.
Todos os avisos sobre restrições vão desaparecer.
Depois disso, a visualização Design vai ficar como no exemplo a seguir, com ImageView
no centro e Button
logo abaixo dela.
Talvez você veja um aviso sobre a ImageView
na Component Tree, informando que uma descrição de conteúdo precisa ser adicionada à ImageView
. Não se preocupe com esse aviso por enquanto. Mais para a frente no codelab, você vai definir a descrição do conteúdo da ImageView
com base na imagem do dado exibida. Essa mudança vai ser feita no código Kotlin.
3. Adicionar as imagens do dado
Nesta tarefa, você vai fazer o download e adicionar algumas imagens ao app.
Fazer o download das imagens de dados
- Abra este URL para fazer o download de um arquivo ZIP com imagens de dados para o computador. Aguarde a conclusão do download.
- Localize o arquivo no computador, que provavelmente está na pasta Downloads.
- Clique duas vezes para descompactar o arquivo ZIP. Isso vai criar uma nova pasta
dice_images
contendo seis arquivos de imagem de dados, mostrando os valores de 1 a 6.
Adicionar imagens de dados ao app
- No Android Studio, clique em View > Tool Windows > Resource Manager nos menus ou na guia Resource Manager à esquerda da janela Project.
- Clique em + abaixo de Resource Manager e selecione Import drawables. Isso abre o navegador de arquivos.
- Encontre e selecione os seis arquivos de imagem de dados. Você pode selecionar o primeiro arquivo e, em seguida, segurar a tecla
Shift
e selecionar os outros arquivos. - Clique em Open.
- Clique em Next e em Import para confirmar que você quer importar os seis recursos.
- Se os arquivos tiverem sido importados corretamente, as seis imagens vão aparecer no Resource Manager (app>res>drawable).
Bom trabalho! Na próxima tarefa, você vai usar essas imagens no app.
Importante: você vai poder se referir a essas imagens no código em Kotlin com os IDs de recurso:
R.drawable.dice_1
R.drawable.dice_2
R.drawable.dice_3
R.drawable.dice_4
R.drawable.dice_5
R.drawable.dice_6
4. Usar as imagens de dados
Substituir a imagem de avatar do exemplo
- No Design Editor, selecione
ImageView
. - Em Attributes, na seção Declared Attributes, encontre o atributo srcCompat da ferramenta, definido como a imagem do avatar.
Não esqueça que o atributo das ferramentas srcCompat usa a imagem fornecida somente na visualização Design do Android Studio. A imagem só é exibida para os desenvolvedores durante a criação do app, mas não quando o app é executado no emulador ou em um dispositivo.
- Clique na visualização pequena do avatar. Um caixa de diálogo será aberta para escolher um novo recurso a ser usado para essa
ImageView
.
- Selecione o drawable
dice_1
e clique em OK.
A ImageView
ocupa a tela inteira.
Em seguida, você vai ajustar a largura e a altura da ImageView
para não ocultar o Button
.
- Na janela Attributes em Constraints Widget, localize os atributos layout_width e layout_height. No momento, eles estão definidos como wrap_content, o que significa que
ImageView
terá a mesma altura e largura que o conteúdo (a imagem de origem) dentro dela. - Em vez disso, defina uma largura fixa de 160 dp e uma altura fixa de 200 dp na
ImageView
. Pressione Enter.
Agora, a ImageView
ficou muito menor.
Você pode achar que o Button
está muito perto da imagem.
- Em Constraint Widget, configure uma margem de 16 dp acima do botão.
Assim que a visualização Design for atualizada, o app vai ficar muito melhor.
Mudar a imagem do dado ao clicar no botão
O layout foi corrigido, mas a classe MainActivity
precisa ser atualizada para usar as imagens do dado.
No momento, há um erro no app no arquivo MainActivity.kt
. Se você tentar executar o aplicativo, o seguinte erro de compilação será exibido:
Isso ocorre porque seu código ainda está fazendo referência à TextView
excluída do layout.
- Abra
MainActivity.kt
(app > java > com.example.diceroller > MainActivity.kt).
O código se refere a R.id.textView
, mas o Android Studio não reconhece essa visualização.
- No método
rollDice()
, selecione e exclua todos os códigos que se referem aTextView
.
// Update the TextView with the dice roll
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = dice.roll().toString()
- Ainda em
rollDice()
, crie uma nova variável chamadadiceImage
do tipoImageView
. Defina essa variável da mesma forma que aImageView
do layout. Use o métodofindViewById()
e transmita oR.id.imageView
, que é o ID de recurso daImageView
, como o argumento de entrada.
val diceImage: ImageView = findViewById(R.id.imageView)
Se você está se perguntando como descobrir o ID de recurso exato da ImageView
, confira o id na parte de cima da janela Attributes.
Ao se referir a esse ID de recurso no código em Kotlin, digite exatamente o mesmo ID ("i" minúsculo, "V" maiúsculo e sem espaços). Caso contrário, o Android Studio vai exibir um erro.
- Adicione esta linha de código para testar se é possível atualizar corretamente a
ImageView
ao clicar no botão. O valor resultante do dado nem sempre será "2", mas use a imagemdice_2
para o teste.
diceImage.setImageResource(R.drawable.dice_2)
O código chama o método setImageResource()
na ImageView
, transmitindo o ID de recurso para a imagem dice_2
. Isso vai atualizar a ImageView
na tela para mostrar a imagem dice_2
.
O método rollDice() vai ficar assim:
private fun rollDice() {
val dice = Dice(6)
val diceRoll = dice.roll()
val diceImage: ImageView = findViewById(R.id.imageView)
diceImage.setImageResource(R.drawable.dice_2)
}
- Execute o app para verificar se ele funciona sem erros. O app será aberto com uma tela em branco, somente com o botão Jogar.
Ao tocar no botão, a imagem de um dado mostrando o número dois aparecerá. Ótimo!
Você conseguiu mudar a imagem de acordo com o toque no botão. Você está quase no fim.
5. Exibir a imagem correta com base no número do dado
É claro que o valor resultante do dado nem sempre será 2. Use a lógica do fluxo de controle aprendida no codelab Adicionar comportamento condicional ao jogar dados para que a imagem adequada seja exibida na tela dependendo do resultado aleatório do dado.
Antes de começar a digitar o código, pense no conceito de como será o comportamento do app, programando um pseudocódigo que descreva o que vai acontecer. Exemplo:
Se o usuário tirar 1, exibir a imagem dice_1
.
Se o usuário tirar 2, exibir a imagem dice_2
.
etc...
O pseudocódigo acima pode ser escrito com instruções if / else
em Kotlin com base no valor resultante do dado.
if (diceRoll == 1) {
diceImage.setImageResource(R.drawable.dice_1)
} else if (diceRoll == 2) {
diceImage.setImageResource(R.drawable.dice_2)
}
...
No entanto, escrever if / else
para cada um dos casos pode ser muito repetitivo. A mesma lógica pode ser expressa de forma mais simples com uma instrução when
. Isso é mais conciso (usa menos código). Use essa abordagem no seu app.
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
...
Atualizar o método rollDice()
- No método
rollDice()
, exclua a linha de código que define o ID de recurso de imagem comodice_2
todas as vezes.
diceImage.setImageResource(R.drawable.dice_2)
- Substitua por uma instrução
when
, que atualiza aImageView
com base no valor dediceRoll
.
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
O método rollDice()
deve ficar assim quando você fizer as mudanças.
private fun rollDice() {
val dice = Dice(6)
val diceRoll = dice.roll()
val diceImage: ImageView = findViewById(R.id.imageView)
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
}
- Execute o app. Ao clicar no botão Jogar, a imagem muda para outros valores além de 2. Funcionou!
Otimizar o código
Caso queira escrever um código ainda mais conciso, faça as seguintes mudanças nele. Elas não têm nenhum impacto visível para o usuário do app, mas deixam o código mais curto e menos repetitivo.
Talvez você tenha notado que a chamada para diceImage.setImageResource()
aparece seis vezes na instrução when.
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
Só o que muda entre cada caso é o ID de recurso que está em uso. Isso significa que é possível criar uma variável para armazenar o ID de recurso a ser usado. Assim, é possível chamar diceImage.setImageResource()
apenas uma vez no código e transmitir o ID de recurso correto.
- Substitua o código acima pelo seguinte.
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
6 -> R.drawable.dice_6
}
diceImage.setImageResource(drawableResource)
Um novo conceito aqui é que uma expressão when
pode retornar um valor. Com esse novo snippet de código, a expressão when
retorna o ID de recurso correto, que será armazenado na variável drawableResource
. É possível usar essa variável para atualizar o recurso de imagem exibido.
- Observe que
when
agora está sublinhado em vermelho. Se você passar o cursor sobre ele, verá uma mensagem de erro: 'when' expression must be exhaustive, add necessary 'else' branch, (a expressão 'when' precisa ser completa, adicione a ramificação 'else' necessária).
O erro ocorre porque o valor da expressão when
é atribuído a drawableResource
, portanto, when
precisa ser completa. Ela precisa processar todos os casos possíveis para que um valor seja sempre retornado, mesmo em um dado de 12 lados. O Android Studio sugere a adição de uma ramificação else
. Isso pode ser corrigido mudando o caso de 6
para else
. Os casos de 1
a 5
são os mesmos, mas todos os outros, incluindo 6
, serão processados por else
.
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
diceImage.setImageResource(drawableResource)
- Execute o app para verificar se ele ainda funciona corretamente. Faça vários testes para garantir que todos os números sejam exibidos com as imagens de 1 a 6.
Definir uma descrição de conteúdo adequada em ImageView
Agora que você substituiu o valor resultante do dado por uma imagem, os leitores de tela não conseguem saber qual número foi tirado. Para corrigir isso, após atualizar o recurso de imagem, atualize a descrição do conteúdo de ImageView
. A descrição do conteúdo precisa ser uma descrição de texto sobre o que é exibido na ImageView
para que os leitores de tela consigam descrevê-la.
diceImage.contentDescription = diceRoll.toString()
Os leitores de tela podem ler essa descrição de conteúdo em voz alta. Dessa forma, se o resultado da imagem "6" for exibido na tela, a descrição do conteúdo será lida em voz alta como "6".
6. Adotar boas práticas de programação
Criar uma experiência de lançamento mais útil
Quando o usuário abre o app pela primeira vez, ele está em branco e somente o botão Jogar é exibido, o que é estranho. Os usuários podem não saber o que esperar. Por esse motivo, mude a interface para exibir um dado com número aleatório ao iniciar o app pela primeira vez e criar a Activity
. Dessa forma, é mais provável que os usuários entendam que, ao clicar no botão Jogar, será feito o lançamento de um dado.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener { rollDice() }
// Do a dice roll when the app starts
rollDice()
}
Adicionar comentário ao código
Adicione comentários ao código para descrever o que está acontecendo no código que você escreveu.
Depois que você fizer todas essas mudanças, o método rollDice()
vai ficar como mostra o exemplo abaixo.
/**
* Roll the dice and update the screen with the result.
*/
private fun rollDice() {
// Create new Dice object with 6 sides and roll the dice
val dice = Dice(6)
val diceRoll = dice.roll()
// Find the ImageView in the layout
val diceImage: ImageView = findViewById(R.id.imageView)
// Determine which drawable resource ID to use based on the dice roll
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
// Update the ImageView with the correct drawable resource ID
diceImage.setImageResource(drawableResource)
// Update the content description
diceImage.contentDescription = diceRoll.toString()
}
Para ver o arquivo MainActivity.kt
completo, consulte o link do código da solução no GitHub na próxima etapa.
Você terminou o app Dice Roller. Agora você pode levar esse app para a próxima noite de jogos com os amigos.
7. Código da solução
O código da solução para este codelab está no projeto e no módulo mostrados abaixo.
Para encontrar o código deste codelab e abri-lo no Android Studio, faça o seguinte.
Acessar o código
- Clique no URL fornecido. Isso abre a página do GitHub referente ao projeto em um navegador.
- Na página do GitHub do projeto, clique no botão Code, que vai mostrar uma caixa de diálogo.
- Na caixa de diálogo, clique no botão Download ZIP para salvar o projeto no seu computador. Aguarde a conclusão do download.
- Localize o arquivo no computador. Geralmente ele é salvo na pasta Downloads.
- Clique duas vezes para descompactar o arquivo ZIP. Isso cria uma nova pasta com os arquivos do projeto.
Abrir o projeto no Android Studio
- Inicie o Android Studio.
- Na janela Welcome to Android Studio, clique em Open an existing Android Studio project.
Observação: caso o Android Studio já esteja aberto, selecione a opção File > New > Import Project.
- Na caixa de diálogo Import Project, vá até a pasta descompactada do projeto, que provavelmente está na pasta Downloads.
- Clique duas vezes nessa pasta do projeto.
- Aguarde o Android Studio abrir o projeto.
- Clique no botão Run
para criar e executar o app. Confira se ele é criado da forma esperada.
- Procure os arquivos do projeto na janela de ferramentas Project para ver como o app está configurado.
8. Resumo
- Use
setImageResource()
para mudar a imagem exibida naImageView
. - Use declarações de fluxo de controle, como expressões
if / else
ouwhen
, para processar diferentes casos no app. Por exemplo, exibir imagens diferentes em circunstâncias diferentes.
9. Saiba mais
10. Praticar por conta própria
Faça o seguinte:
- Adicione outro dado ao app. Assim, o botão Roll vai mostrar o resultado de dois dados. Quantas
ImageViews
são necessárias no seu layout? Como isso afeta o código deMainActivity.kt
?
Confira seu trabalho:
O app final precisa ser executado sem erros e exibir os dois dados.