Adicionar imagens ao app Dice Roller

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 ao número dos lados que foram tirados, o que cria uma experiência muito mais visual e aprimorada.

c7f0d42525da7431.png

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

  1. 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:

2e8416293e597725.png

  1. Abra activity_main.xml (app > res > layout > activity_main.xml). O Layout Editor vai abrir.

Excluir a TextView

  1. No Layout Editor, selecione a TextView na seção Component Tree.

a6fc189dac34ee71.png

  1. Clique com o botão direito e escolha Delete ou pressione a tecla Delete.
  2. Ignore o aviso no Button por enquanto. Isso vai ser corrigido na próxima etapa.

Adicionar uma ImageView ao layout

  1. Arraste uma ImageView da Palette para a visualização Design, acima do Button.

91f6e2be0a01fbf.png

  1. 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.

824493e9927da401.png

  1. Pressione OK. A visualização Design do app vai ficar assim.

f9d5ee87018baee.png

  1. Em Component Tree, você vai observar dois erros. O Button não tem uma restrição vertical, e a ImageView não tem restrição vertical nem horizontal.

b8c3b83124c31ff.png

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.

  1. Adicione restrições horizontais à ImageView. Conecte o lado esquerdo da ImageView à borda esquerda do ConstraintLayout pai.
  2. Conecte o lado direito da ImageView à borda direita do pai. Isso vai centralizar a ImageView horizontalmente dentro do layout pai.

9848bb6319e11777.png

  1. Adicione uma restrição vertical à ImageView, conectando a parte de cima da ImageView à parte de cima do pai. A ImageView vai deslizar para o topo do ConstraintLayout.

2d8d134e6292d48f.png

  1. Adicione uma restrição vertical ao Button, conectando a parte de cima do Button à parte de baixo da ImageView. O Button vai deslizar até ficar abaixo da ImageView.

b6d3dcee6c7a51fc.png

  1. Agora, selecione a ImageView novamente e adicione uma restrição vertical que conecta a parte de baixo da ImageView à parte de baixo do layout pai. Isso centraliza a ImageView verticalmente no ConstraintLayout.

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.

1b05a6d2fd56459f.png

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

  1. Abra este URL para fazer o download de um arquivo ZIP com imagens de dados para o computador. Aguarde a conclusão do download.
  2. Localize o arquivo no computador, que provavelmente está na pasta Downloads.
  3. 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.

43c95351759ada02.png

Adicionar imagens de dados ao app

  1. No Android Studio, clique em View > Tool Windows > Resource Manager nos menus ou na guia Resource Manager à esquerda da janela Project.
  2. Clique em + abaixo de Resource Manager e selecione Import drawables. Isso abre o navegador de arquivos.

67186ea5d631bc8a.png

  1. 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.
  2. Clique em Open.
  3. Clique em Next e em Import para confirmar que você quer importar os seis recursos.

a45dff94a19e2722.png

a7ad66d623ac73c2.png

  1. Se os arquivos tiverem sido importados corretamente, as seis imagens vão aparecer no Resource Manager (app>res>drawable).

ab68f82b385fc83e.png

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

  1. No Design Editor, selecione ImageView.
  2. 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.

  1. 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.

d8a26941179b3bdf.png

  1. Selecione o drawable dice_1 e clique em OK.

A ImageView ocupa a tela inteira.

1072e9fdd637afd9.png

Em seguida, você vai ajustar a largura e a altura da ImageView para não ocultar o Button.

  1. 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.
  2. 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.

9579582d8775e688.png

Você pode achar que o Button está muito perto da imagem.

  1. Em Constraint Widget, configure uma margem de 16 dp acima do botão.

8c647d6ae28ef3a6.png

Assim que a visualização Design for atualizada, o app vai ficar muito melhor.

b53f7379bfba8c27.png

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:

aaecce207cb5fc7.png

Isso ocorre porque seu código ainda está fazendo referência à TextView excluída do layout.

  1. 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.

3a923aa53fc3ba8a.png

  1. No método rollDice(), selecione e exclua todos os códigos que se referem a TextView.
// Update the TextView with the dice roll
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = dice.roll().toString()
  1. Ainda em rollDice(), crie uma nova variável chamada diceImage do tipo ImageView. Defina essa variável da mesma forma que a ImageView do layout. Use o método findViewById() e transmita o R.id.imageView, que é o ID de recurso da ImageView, 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.

cbfc9d5e01a04e32.png

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.

  1. 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 imagem dice_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)
}
  1. 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.

c29b50554a31d30f.png

Ao tocar no botão, a imagem de um dado mostrando o número dois aparecerá. Ótimo!

7df72d671b22853f.png

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()

  1. No método rollDice(), exclua a linha de código que define o ID de recurso de imagem como dice_2 todas as vezes.
diceImage.setImageResource(R.drawable.dice_2)
  1. Substitua por uma instrução when, que atualiza a ImageView com base no valor de diceRoll.
   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)
   }
}
  1. Execute o app. Ao clicar no botão Jogar, a imagem muda para outros valores além de 2. Funcionou!

ec209952f84b81bd.png 32fc8979b1984e00.png

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.

  1. 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.

  1. 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)
  1. 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 IU 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()
}

ec209952f84b81bd.png

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

  1. Clique no URL fornecido. Isso abre a página do GitHub referente ao projeto em um navegador.
  2. Na página do GitHub do projeto, clique no botão Code, que vai mostrar uma caixa de diálogo.

5b0a76c50478a73f.png

  1. Na caixa de diálogo, clique no botão Download ZIP para salvar o projeto no seu computador. Aguarde a conclusão do download.
  2. Localize o arquivo no computador, que provavelmente está na pasta Downloads.
  3. Clique duas vezes para descompactar o arquivo ZIP. Isso vai criar uma nova pasta com os arquivos do projeto.

Abrir o projeto no Android Studio

  1. Inicie o Android Studio.
  2. Na janela Welcome to Android Studio, clique em Open an existing Android Studio project.

36cc44fcf0f89a1d.png

Observação: caso o Android Studio já esteja aberto, selecione a opção File > New > Import Project.

21f3eec988dcfbe9.png

  1. Na caixa de diálogo Import Project, vá até a pasta descompactada do projeto, que provavelmente está na pasta Downloads.
  2. Clique duas vezes nessa pasta do projeto.
  3. Aguarde o Android Studio abrir o projeto.
  4. Clique no botão Run 11c34fc5e516fb1c.png para criar e executar o app. Confira se ele é compilado da forma esperada.
  5. 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 na ImageView.
  • Use declarações de fluxo de controle, como expressões if / else ou when, 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:

  1. 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 de MainActivity.kt?

Confira seu trabalho:

O app final precisa ser executado sem erros e exibir os dois dados.