Como fazer um aplicativo quiz para Android

Android SDK

Como fazer um aplicativo quiz para Android

Luiz Duarte
Escrito por Luiz Duarte em 10/06/2017
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Um dos aplicativos mais lucrativos que já fiz foi um que fiz para a Renault. Falar assim soa bem imponente né? A história é um pouco menos glamurosa que isso, mas basta saber que o app em questão era um quiz (jogo de perguntas e respostas) para o evento Renault Experience do ano de 2013, visando testar os conhecimentos dos visitantes do evento que aconteceu na UFPR.

Obviamente eu não posso fornecer os fontes do app aqui, uma vez que eu vendi o projeto e os direitos intelectuais, mas posso ensinar vocês a fazer uma versão mais simples que depois vocês podem incrementar!

Veremos neste post:

  1. Criando uma splash screen
  2. Criando o quiz
  3. Criando a tela de resposta certa/errada
  4. Deixando tudo mais dinâmico
  5. Adicionando mais perguntas ao quiz
  6. Finalizando o app

Vamos lá?

Atenção: se esse é seu primeiro app Android, sugiro dar uma olhada neste outro post aqui que é mais básico: Tutorial Android Studio.

#1 – Criando uma splash screen

A splash screen é a tela inicial de qualquer jogo, onde temos o logo/título do mesmo e um botão de jogar que inicia o jogo em si, bem fácil de criar.

Crie um novo projeto no Android Studio com o nome de LuizQuiz (ok, pode criar com outro nome se quiser…) e com uma Empty Activity dentro. Nossa MainActivity será a Splash Screen, e no layout dela, vamos adicionar uma ImageView e um Button com a propriedade text=Jogar e id=btnJogar. A propriedade src da ImageView deve apontar para uma imagem na sua pasta res/drawable, sendo que aqui eu criei uma usando o Canva.com, o mesmo software online que uso para criar as capas de meus livros.

A imagem abaixo mostra como deve se parecer essa tela depois de pronta (apenas posicione os elementos e depois clique no botão de Infer Constraints como explicado no Tutorial de Constraint Layout). Quando você arrastar uma ImageView para seu layout é bem provável que o Android Studio já abra uma tela para procurar pela sua imagem:

LuizQuiz

A cor laranja de fundo eu coloquei colocando a propriedade:

na tag de ConstraintLayout que fica na raiz do XML de layout. Se quiser um botão mais bonito do que o que usei, basta criar uma imagem de botão e usar um ImageButton com essa imagem ao invés do Button normal.

Caso esteja com problemas para criar essa tela, segue abaixo o código XML completo:

Agora clique com o botão direito do mouse sobre a pasta do projeto e mande adicionar uma nova Activity do tipo EmptyActivity à ele, que vamos chamar de QuizActivity. Programaremos esta Activity mais tarde, por enquanto apenas deixe ela lá, com seu layout XML em branco mesmo.

Para finalizar nossa Splash Screen, temos de permitir que quando o usuário tocar no botão Jogar, que o app troque de tela, para a QuizActivity que acabamos de criar. Para fazer isso, primeiro sinalizei no XML do Button a propriedade onClick=btnJogarOnClick (o código XML anterior já inclui essa alteração). Esse é o nome do método que deve existir na MainActivity que vai ser disparado quando o botão for clicado.

O método em questão deve ser como abaixo, invocando a tela seguinte através de um Android Intent. Coloque-o na sua MainActivity, logo após o método onCreate que já vem por padrão.

Com isso, a sua splash screen já deve estar funcionando. Agora vamos à tela do quiz em si.

#2 – Criando o quiz

Vamos ter uma única Activity para exibir as perguntas, sendo que cada pergunta será exibida uma por vez. Para começar, vamos estruturar o layout XML da QuizActivity para que mostre uma pergunta falsa, apenas para deixarmos tudo pronto para as verdadeiras que vamos adicionar depois.

Vamos adicionar um TextView para a pergunta (coloque uma qualquer no text dele e defina o appearance como algo maior que o padrão Small), um RadioGroup para as opções (cada opção deve ser um RadioButton diferente dentro do RadioGroup) e um botão com text=Responder. A ideia é que sua interface se pareça com a abaixo:

LuizQuiz

Se estiver tendo problemas para posicionar os elementos na tela com o ConstraintLayout, você pode usar outro como Relative Layout ou mesmo Linear Layout, que são mais fáceis (e menos poderosos). Eu faço rapidamente jogando os widgets na tela, e quando o Infer Constraints (o botão com ícone de estrela amarela que fica logo acima do Layout Editor) não resolve tudo sozinho, eu crio as constraints horizontais de cada widget para fixá-lo à tela e depois seleciono todos widgets segurando Ctrl e uso a opção Center Vertically que aparece clicando com o botão direito do mouse, o que cria as constraints verticais automaticamente.

Se achar que é muito trabalho, apenas copie o layout XML abaixo que representa a tela acima:

O fluxo que quero fazer é o seguinte: você clica em responder, vai para uma tela que te diz se você acertou ou não, e depois volta para essa tela com uma nova pergunta para responder. Para fazer esse fluxo, precisamos adicionar uma nova activity ao projeto (do tipo Empty) que chamarei de RespostaActivity. Não vamos mexer nela agora, apenas crie a mesma vazia.

Volte ao XML da QuizActivity e mude os ids de alguns componentes para:

  • TextView: pergunta;
  • RadioGroup: rgRespostas;
  • RadioButton das respostas: rbResposta1 até rbResposta4;
  • Button: btnResponder;

E no Button, adicione na propriedade onClick=btnResponderOnClick, que é o nome do método que vamos criar na classe QuizActivity para fazer a troca de tela. Mas desta vez não será uma troca de tela simples, pois passaremos a informação se o usuário acertou ou não a pergunta, para que o app avise ele. Para fazer isso, usaremos os Extras.

Note que carreguei o widget RadioGroup para uma variável local para poder pegar o Id do RadioButton interno que foi selecionado. Já fiz isso em outros tutoriais aqui no blog, nada de novo por aqui. Também comparei fixamente qual é a resposta certa, comparando com o id do RadioButton da primeira resposta (mudaremos isso mais tarde).

Com isso encerramos essa etapa da sua tela de quiz. Voltaremos à ela mais tarde.

Atenção: sugiro executar o emulator Android (ou testar de alguma outra maneira) a cada uma das etapas deste tutorial para se certificar que está tudo funcionando como deveria. São etapas simples de troca de tela, mas que se não estiverem funcionando agora, vão te gerar problemas depois.

#3 – Criando a tela de resposta certa/errada

Agora vamos terminar a nossa RespostaActivity. Ela vai ser bem simples, vai mostrar uma imagem de sucesso ou de fracasso, conforme a resposta que chegar da tela anterior. Neste momento, essa avaliação é falsa, porque a pergunta da tela anterior também o é. Estou apenas estruturando toda aplicação contigo para depois colocarmos a “inteligência” nela.

Nesta tela, além do fundo laranja que você pode copiar dos outros layouts (propriedade background, lembra?) nós vamos adicionar um ImageView com uma de duas imagens que você pode obter facilmente na Internet, designando sucesso ou fracasso. Também vou adicionar um TextView logo abaixo com a mensagem em texto, caso a imagem não seja óbvia. Não, não vou colocar um botão de voltar aqui, vamos fazer algo mais interessante logo mais à frente.

A sua interface de resposta falsa deve se parecer com essa:

LuizQuiz

Caso esteja com alguma dificuldade, segue o layout XML completo abaixo. Note como coloquei ids para o TextView (resposta) e a ImageView (imgResposta), visando manipulá-las mais tarde via código Java:

A dinâmica que vamos fazer com essa tela é a seguinte: o usuário vai responder a pergunta, vai ver esta tela pra saber se acertou ou errou, e depois o próprio app vai sair desta tela e mostrar a próxima pergunta. Para fazer isso automaticamente (e não deixar o usuário descansar), usaremos uma Thread que vai esperar 5s para finalizar a Thread atual, exibindo novamente a tela anterior.

O código abaixo mostra como fazer isso, dentro do onCreate da própria Activity de resposta.

Aqui dois pontos merecem atenção: primeiro, o uso de um thread que ao executar ficará 2000ms (ou 2s) esperando até finalizar a Activity atual. Segundo, se você estava se perguntando como que meu app estava sem a ActionBar do Android no topo (aquele barra azul), eu faço isso chamando getSupportActionBar().hide() como exibido acima.

Se você testar agora o app, você vai ver que após responder a sua única pergunta estática, a tela de resposta vai aparecer e depois voltará para a tela da pergunta. Você pode inclusive testar isso diversas vezes.

Curso React Native

#4 – Deixando tudo mais dinâmico

Para esta tela ficar um pouco mais inteligente, mesmo que provisoriamente, vamos verificar se o usuário acertou ou errou a pergunta da tela anterior para exibir a imagem correspondente. Primeiro, certifique-se de ter as duas imagens na sua pasta drawables (tem vários sites na Internet que você pode baixá-las gratuitamente). Eu chamei uma de acertou e outra de errou.

Através do código abaixo estou verificando se a pergunta anterior foi respondida corretamente ou não e mostra a imagem certa na tela, usando a mesma ImageView, bem como mudando o texto da TextView. Esse código vai no onCreate da RespostaActivity, antes do trecho com a thread que programei antes.

Caso esse código não esteja claro o suficiente, segue uma explicação:

  • nas duas primeiras linhas, carrego em variáveis locais os widgets que irei manipular.
  • na sequência, pego o Intent que foi usado para chegar nessa Activity, visando obter o Extra “acertou” que foi passado junto ao Intent na QuizActivity. Essa informação tem um booleano indicando true ou false.
  • com isso, faço um if para ver se a pessoa marcou a resposta certa e defino a imagem e texto correspondentes.

Outro comportamento que precisamos deixar nosso app preparado é o de quando voltamos à tela de Quiz ele deve exibir outra pergunta, já que hoje ele mostra sempre a mesma. Por ora, vamos apenas trocar aquela pergunta por outra nesta ocasião, que deve ser programada no onRestart da QuizActivity (evento disparado quando esta tela volta a ficar visível).

Para que esse onRestart funcione corretamente, temos de fazer algumas outras alterações nesta QuizActivity. Bem no topo da classe, antes do onCreate, vamos declarar algumas variáveis:

Basicamente estamos declarando variáveis que vamos usar mais tarde, mas uma merece mais atenção aqui: respostaCerta. Nela definiremos qual dos RadioButtons da tela contém a resposta certa para a pergunta atual. Por ora vamos deixar fixo, mas mais tarde esse valor será dinâmico.

Agora, dentro do onCreate desta QuizActivity, vamos carregar os widgets:

E por fim, o método de clique do botão Responder deve ser ajustado para usar a nossa variável respostaCerta, como mostra o bloco completo abaixo, que inclui algumas outras alterações menores como a “desmarcação” da resposta (para não ficar vindo marcado depois).

Opa, mas que variável ‘pontos’ é aquela ali? É um contador de respostas certas. Apenas declare ele como uma variável normal no corpo da classe que deve funcionar. Note que estou passando essa variável para a tela de resposta, para que seja possível personalizar a mensagem da mesma, informando os pontos, etc (use sua criatividade aqui).

Com isso, você consegue testar novamente. A primeira pergunta será a default do descobrimento do Brasil, cuja resposta certa é 1. Independente se você acertar ou errar (o que será apresentando na tela de resposta), você voltará à tela do Quiz com a nova pergunta do site, que nesse caso a resposta correta é 2. Teste no AVD antes de seguir adiante.

#5 – Adicionando mais perguntas ao quiz

Agora que já estruturamos toda nossa aplicação, é hora de adicionarmos as perguntas à ela. Para que este tutorial não fique muito extenso não vou usar banco de dados aqui, mas apenas perguntas salvas na memória do app mesmo, evitando conceitos que podem ser complexos para os iniciantes.

Quem quiser salvar e retornar perguntas de um banco local no app, pode dar uma olhada neste tutorial de SQLite aqui. Já se suas perguntas vão estar em um banco remoto, veja este outro tutorial aqui sobre acesso remoto à banco de dados.

Para armazenar as questões em memória, vamos criar uma nova classe Java em nosso projeto chamada Questao, contendo variáveis para as alternativas e para a resposta certa.

Agora vamos voltar à nossa QuizActivity e vamos criar uma estrutura de dados em memória com uma série de objetos do tipo Questao, incluindo suas alternativas, resposta certa, etc. Não vai ser um primor de arquitetura, mas vai funcionar para um exemplo didático. Coloque esse código no topo da QuizActivity.

Agora, ainda na QuizActivity, vamos criar um método genérico de carregar a próxima questão na tela, que podemos colocar em qualquer parte da Activity. Esse método remove a questão também, para que elas não se repitam a cada chamada.

Em todos os locais em que precisamos carregar uma questão, vamos chamá-lo, como por exemplo no onCreate da QuizActivity:

e o no evento onRestart:

Notem que o onRestart ficou bem mais simples, porque praticamente ele era esse nosso novo método carregarQuestao().

E antes de fazermos um novo teste, lembra que mudei o click do botão de responder para passar a informação dos pontos para a tela de resposta? Então vamos pegar essa informação lá para exibir na tela, informando o usuário de quantos pontos ele já tem. O código abaixo ilustra isso, no onCreate da RespostaActivity (ache-o no onCreate e faça as alterações para manipular os pontos):

Se testarmos agora, teremos muitas coisas novas e interessantes como múltiplas perguntas, contagem de pontos, etc. No entanto, após você responder à última pergunta, o app quebra, certo?

#6 – Finalizando o app

Após o usuário responder todas perguntas ele deve ser redirecionado para uma tela com o seu desempenho. Sabemos que ele respondeu todas perguntas quando o nosso List<Questao> está vazio, dentro do método carregarQuestao. Mas antes de mexer nele, vamos trabalhar na nossa tela de sucesso.

Pensei em uma tela de sucesso bem simples, onde vamos exibir uma imagem e uma mensagem, falando do resultado do usuário. Note que isso é exatamente o que já temos na tela de resposta. Que tal personalizarmos ela para exibir também esse desempenho final?

Primeiro, vamos no método carregarQuestao() para evitar que o app quebre novamente. O que temos de fazer é bem simples: se a lista de questões estiver vazia, devemos jogar o usuário para a activity de Resposta, sem o Extra informando se ele acertou ou não, apenas com os pontos. Também vamos derrubar esta Activity pois não temos mais questões pra ela.

Agora, antes de começarmos a editar o código Java da RespostaActivity para exibir o desempenho do usuário, pegue na Internet algumas imagens que possam ser usadas para enfatizar se o usuário foi bem ou mal no quiz. Eu baixei duas imagens, uma para quem acertou menos de 3 questões (ruim) e outra para quem acertou 3 ou mais (bom). Coloque suas imagens na pasta res/drawables, assim como as outras imagens.

Agora, adicione um Button no layout da tela de resposta com o text=Jogar Novamente e o id=btnJogarNovamente. Também adicione na propriedade onClick dele o nome do método btnJogarNovamenteOnClick que criaremos mais abaixo.

LuizQuiz

No onCreate da nossa RespostaActivity deveremos verificar se veio apenas o Extra de pontos, sem o Extra informando se acertou a questão anterior ou não. Nesse caso, devemos ver qual imagem exibir (feliz, triste, acerto ou erro) e se devemos exibir ou não o botão (deve ser exibido somente no caso de jogo finalizado).

O código do onCreate completo da RespostaActivity deve ficar dessa maneira:

Além disso, temos o botão de Jogar Novamente. O Clique dele deve reiniciar o jogo. Para isso, vamos iniciar novamente a QuizActivity que havíamos finalizado antes, para que tudo volte a ser como era novamente.

Claro, o ideal seria você pegar um conjunto novo de perguntas, aqui o jogador terá de responder novamente as mesmas 4 perguntas que já vem na memória do quiz. Também seria bem interessante trocar o ícone da aplicação, que fica na pasta mipmap e adicionar alguma forma de monetização (para ganhar uns trocados).

Mas estes e outros ajustes para deixar o app com a sua cara, eu deixo para você.

Até a próxima!

Curso Beholder

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

25 Replies to “Como fazer um aplicativo quiz para Android”

Vinicius Nunes

Olá Luiz. Fiz todo o passo a passo mas ele está disparando um erro nessa linha ” RadioButton rb = (RadioButton)findViewById(rgRespostas.getCheckedRadioButtonId()); “. Ele está dando um erro no método getCheckedRadioButtonId(). Quando eu clico no botão responder exibe “O aplicativo parou”

Luiz Fernando Jr

Provavelmente o seu rgRespostas não está sendo inicializado no onCreate com o findViewById(R.id.rgRespostas) ou algo do tipo. Pra saber o erro específico, você pode usar um try/catch e logar a mensagem de erro. Esse “aplicativo parou” é genérico quando dá crash.

Vinicius Nunes

Vou verificar e te dou o retorno. Obrigado pela resposta amigo!!

Aldenor

Olá meu caro Vinicius Nunes, eu baixei o seu código e ao clicar no botão responder a pergunta, dá erro. Já tentei muitas vezes e não consigo ver onde está o erro. Você poderia me ajudar?

Vinicius Nunes

Oi meu amigo. Eu não tive esse erro e nem em demais telefones. Todos funcionaram de boa. Inclusive eu fiz algumas alterações e apresentei como projeto na faculdade rs. Teve um S7 de um amigo em que ele dizia que quando clicava em responder também dava erro, mas não conseguimos descobrir o motivo. Abraços.

Vinicius Nunes

Amigo, deu tudo certo, era justamente isso! Pode me tirar uma outra duvida? Em cada questão eu quero adicionar uma imagem correspondente a pergunta, como eu implemento isso de forma que ele vá alterando conforme sua pergunta?
E futuramente eu quero inserir um áudio, caso o usuário erre, soe um som, caso acerte, soe outro. Quando terminar soe um som de tipo vitoria (caso + que a metade de acertos). Forte abraço.

Fábio sm

Olá Vinícius Nunes, o meu deu o mesmo erro que o seu, não conseguir resolver! Você fez como, poderia me ajudar?

Vinicius Nunes

Olá Fábio, eu apenas declarei o rgRespostas = (RadioGroup)findViewById(R.id.rgRespostas); no onCreate da Activity, juntamente com os demais elementos e funcionou! Caso continue a dúvida eu coloquei no meu github, segue o link > https://github.com/viniciusnuunes/MemeQuiz

Fábio sm

Obrigado Vinícius, irei mexer no projeto mais tarde e farei isso. Darei uma olhada no link. Forte abraço!

Luiz Fernando Jr

Para cada questão deverá ter outro atributo: imagem. Nesse atributo você colocará o id da imagem que deve ser carregada. Todas as imagens devem estar na pasta drawables e na tela de pergunta deve ter um ImageView que você deve setar com a imagem da pergunta.

O áudio você deve guardar os arquivos mp3 em uma pasta assets e depois mandar tocar quando quiser usando as APIs de áudio do Android. Terá de dar uma pesquisada, não tenho nenhum material sobre isso aqui no blog, ainda.

Vinicius Nunes

Oi Luiz, eu tentei de diversas formas. Passei na classe Questão como um ImageView, coloquei no método e na activity eu não to conseguindo carrega-la dentro do array que cria as questões. Tentei R.drawable.imagem, tentei também retornando um int mas nada eu consegui 🙁 . Estou com muita dificuldade nisso

Luiz Fernando Jr

Na tela vai um ImageView, na questão vai um int. Para cada questão, esse int deve guardar o R.drawable.nomeDaImagem, que retorna um inteiro. Quando for exibir na tela, tu vai carregar o teu ImageView em uma variável local (com findViewById) e usar o método setImage-alguma-coisa (não lembro direito) passando o id da imagem por parâmetro (que está guardado no objeto Questao).

Lembrando que você deve ter todas as imagens salvas em res/drawables e carregar seus ids nas questões logo que o app iniciar, pois esses ids não são estáticos.

Fábio sm

Olá Luiz Tools! Em primeiro lugar queria parabeniza-lo pela sua boa vontade de ajudar as pessoas com seus magníficos projetos aqui presentes. Está funcionando perfeitamente este projeto, porém, pretendo fazer um Quiz de 100 questões, teria como só dá o resultado completo no final das questões, revelando os acertos ou erros e com opção para o gabarito? Gostaria de implementar outro Button no caso a pessoa queira retornar a questão anterior para uma possível correção e queria também adicionar um temporizador de 30 minutos para responder as questões, sendo que, cada rodada só serão selecionadas 20 questões, e que as mesmas não se repitam ao longo das rodadas. Um forte abraço!

Luiz Fernando Jr

Boa noite Fábio. Primeiramente fico feliz que goste dos meus materiais. Tudo que você falou é perfeitamente possível de implementar. Sugiro que vá tentando implementar uma-a-uma as funcionalidades e, caso tenha algum erro em alguma, me envie por email que poderei lhe ajudar melhor.

Fábio sm

Ok Luiz, farei isto sim! Vou tentando aqui e ver o que sai. Obrigado pela atenção e um forte abraço.

Rafael souza

Luiz Boa Noite,
Pode me ajudar com uma duvida? estou ajudando em um projeto de um app para estudos como trabalho final desse semestre, estou criando uma tele de testes e respostas e utilizando seu tutrial como base, fiz o quiz e estou utilizando como perguntas de história, agora eu queria ter um quiz de Fisíca por exemplo, posso utilizar toda a estrutura que já tenho montada trocar somente as perguntas montando um segundo Array?
como eu posso fazer para quando clicar no botão história ele ler o primeiro array e quando clicar em Fisíca ele ler o segundo array?

Luiz Fernando Jr

Boa tarde Rafael. É possível sim. Use uma segunda lista (ou até mesmo coloque em um banco SQLite, como ensino em outros tutoriais) e quando ele escolher a opção História, salve essa escolha em uma variável que você deve passar às telas seguintes para saber se deve mostrar uma pergunta de História ou de Física.

Marcelo Kiilian

Luiz boa tarde… parabéns pelo post, foi muito útil. Porém estou fazendo um teste com o Android 7 e ele me estoura o erro “FAILED BINDER TRANSACTION !!! (parcel size = 1961940)” com as outras versões funciona muito bem.
Saberia me dizer o porque disso?
As respostas que achei no google falam em tamanho de download. mas não fazemos nenhum download nesse app

Desde já agradeço a atenção

Forte abraço

Luiz Fernando Jr

Bom dia Marcelo. Nunca vi esse erro antes, vou tentar rodar no Android 7 hoje à noite para ver o que acontece.

Marcelo Kiilian

Legal Luiz.. obrigado… as únicas coisas que eu fiz a mais foi um login no facebook, criei uma sessão para levar o nome do usuário para o final, uma msg de alerta para pedir para o jogador selecionar uma resposta caso ele clique no botão responder..

Mas já tirei tudo e não rolou…

Abraços

Marcelo Kiilian

Cara.. achei o problema.. é no login do face… seu código esta perfeito..

Abraços

Vinicius Nunes

Obrigado por compartilhar esse conhecimento Marcelo, eu estava tentando e não achava uma forma de ajeitar esse “bug” (Sou novato)

Marcelo Kiilian

Vinicius, que bom que foi útil.. abraços

Lucas Ft

Boas desde já agradeço pelo seu excelente artigo.
A minha dúvida é se é possível por um temporizador de por exemplo 1 minuto. já pesquisei sobre isso mas não encontro nada em concreto.

Luiz Fernando Jr

Aqui mesmo no blog tem um tutorial de com fazer um app de cronômetro, acho que pode te ajudar. Procura ali pela barra de busca na esquerda. Outra alternativa é usando Threads.