Conheça os segredos da criação de Menus em Android
Atualmente, um aplicativo mobile tem várias funcionalidades que não existiam nos seus primórdios, à evolução foi grande e os desenvolvedores tiveram que acompanhar esta maturação de forma constante. Porém, certos quesitos continuam imutáveis, sendo peças fundamenteis em um bom aplicativo desde os primórdios do mobile, com o bom e velho Java ME. Podemos falar de persistência de dados, podemos falar de interfaces ricas, intuitivas, podemos falar de uso consciente do espaço limitado dos displays, mas não, vamos falar dos menus. É difícil imaginar um aplicativo que não tenha nenhum item de menu presente. A plataforma Android nos fornece várias maneiras de criar menus, deixando um poder muito grande na mão dos desenvolvedores. Veja quais são as opções: •
Menu de opções e barra de ações: nas versões 2.3 e anteriores do Android, o menu é acionado pressionando o botão físico do menu. Ele aparece na parte inferior e pode conter somente 6 itens. Se este número for ultrapassado teremos a sexta opção com o texto “Mais”. Clicando nele o usuário verá as outras opções. Na versão 3.0 e posteriores foi implantado um conceito de barra de ações (Action Bar). Nela, os menus aparecem no canto superior direito. Podem ser mostrados como um menu drop-down ou serem forçados a aparecem sempre na barra superior. Podemos imaginar estes menus como os mais gerais para uma Activity.
•
Menu contextual e contextual action mode: um menu contextual é referente a uma parte específica da tela, como uma View. Por exemplo, podemos ter um botão com o nome de um carro, ao clicar nesta imagem o usuário verá um menu com as seguintes opções: comprar e alugar. No Android 2.3 e anteriores, este menu aparece como uma janela modal. Já nas versões posteriores, devemos utilizar o contextual action mode, que substitui as ações da barra superior por as opções específicas daquela View.
•
Popup menu: como o próprio nome sugere, este tipo de menu, que foi incluído na versão 3.0 do Android, mostra um janela abaixo da View solicitante, caso exista espaço, caso contrário, mostrará encima.
Perceba que o Android oferece uma API completa, suprindo todas as necessidades que possam surgir no nosso projeto em relação a menus. Vamos estuda-los melhor separadamente nas próximas seções. Boa leitura.
Menu de Opções e Action Bar Este tipo de menu é o básico neste conceito, ele abrange as principais opções da sua Activity. Até a versão 2.3 do Android, ele era chamado com a tecla física do menu, porém, a partir da versão 3.0, este já não é mais obrigatório. Tanto é verdade, que já tem alguns aparelhos saindo no mercado sem ele. Ou seja, é muito bom aprendermos as novas formas de utilização de menus, ou seja, Action Bar. Independente desta mudança de paradigma visual, a forma de programação dos menus é quase que totalmente igual nos dois modelos. Basicamente, a maior mudança é mesmo na estética. Veja na Figura 1, um menu sendo mostrado em um AVD (Android Virtual Device) do Android 2.3. Já na Figura 2 estamos pegando um Screenshot da mesma aplicação em um Motorola RAZR i.
Figura 1: menu de opções no Android 2.3
Figura 2: menu de opções no Android 4.0
E como cria-los? Independente da versão de menu que estivermos utilizando, é aconselhável criar um arquivo de recurso para a descrição dos itens de menu. Isso trará alguns benefícios, como: separação do código da Activity e os itens de menu e possibilidade de especialização conforme densidade da tela, internacionalização, ou versão do sistema operacional.
No seu projeto, basta criar uma pasta chamada menu dentro da pasta res, gerada no momento da criação de seu projeto (imaginando que esteja usando a dupla Eclipse + ADT). Lá teremos quantos arquivos XML quisermos. Por exemplo, queremos ter um menu para a lista de clubes de futebol e, outra para a interna de cada time. Poderíamos ter dois arquivos: listahome.xml e internaclube.xml. A regra aqui é que este arquivo tenha como root a tag menu, que servirá como um container para seus itens. Veja o exemplo que criei para gerar as telas das Figuras 1 e 2:
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_cinza" android:orderInCategory="100" android:showAsAction="ifRoom" android:title="Cinza"/> <item android:id="@+id/menu_verde" android:orderInCategory="101" android:showAsAction="ifRoom|withText" android:title="Verde" android:icon="@android:drawable/ic_menu_edit"/> <item android:id="@+id/menu_azul" android:orderInCategory="102" android:showAsAction="ifRoom|withText" android:title="Azul" android:icon="@android:drawable/ic_menu_delete"/> </menu>
Dentro da tag menu poderemos ter quantos itens quisermos. A tag item, por sua vez, pode ter alguns parâmetros, sendo que os principais são estes usados no exemplo. Veja a descrição de cada um deles: •
android:id: serve para identificar o menu item. Ele será utilizado no momento de tratarmos a ação de clique.
•
android:orderInCategory: podemos definir a ordem do menu item em uma determinada categoria.
•
android:title: define o rótulo do item de menu. Para ser um trabalho profissional, este valor deverá estar internacionalizado.
•
android:icon: podemos definir um ícone para o item de menu. Esta imagem pode estar tanto em nosso projeto como, nos próprios recursos que o sistema operacional usa.
•
android:showAsAction: define quando e como o item de menu aparecerá na action bar.
Depois desta definição, podemos sobrescrever o método onCreateOptionsMenu, em nossa Activiy ou Fragment. No Android 2.3 e anteriores, ele será chamado no momento que o botão físico de menu for acionado. No Android 3.0 e superiores, o método será chamado quando a tela for mostrada pela primeira vez. Isso porque se pressupõe que o menu estará sempre visível na barra de ações. Veja como estamos fazendo:
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; }
Precisamos de uma instância de MenuInflater, para isso chamamos o método getMenuInflater(). Esta classe possui o método inflate, passando os itens de menu descritos em um xml para a instância de Menu passada por parâmetro neste método de callback. E como respondo a ações do usuário? Basta apenas sobrescrever o método onOptionsItemSelected, que receberá por parâmetro uma instância de MenuItem, identificando quem ocasionou a chamada deste callback. Veja no código abaixo como responderíamos ao menu que criamos neste artigo:
@Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case R.id.menu_azul: root.setBackgroundColor(Color.BLUE); return true; case R.id.menu_cinza: root.setBackgroundColor(Color.GRAY); return true; case R.id.menu_verde: root.setBackgroundColor(Color.GREEN); return true;
}
default: return super.onOptionsItemSelected(item);
}
Como o método recebe o MenuItem, podemos chamar getItemId e recuperar o id deste item de menu. Esta propriedade foi passada no momento da criação do XML que define o root menu e seus itens. Sendo assim, basta criarmos um código que associa o id com a ação que queremos. No exemplo, estamos mudando a cor do layout principal da Activity. Chamando o método setBackgroundColor, de uma instância de RelativeLayout. Neste momento, nosso aplicativo já responde aos comandos. Veja na Figura 3:
Figura 3: Fundo alterado para a cor azul.
Nesta imagem também podemos exemplificar muito bem uma propriedade dos itens de menu. Quando criamos o arquivo XML definimos a propriedade android:showAsAction como ifRoom e withText. Isso nos diz duas coisas. O ifRoom irá colocar o item de menu no ActionBar, caso tenha espaço. O withText irá mostrar tanto o ícone como o texto, quando tiver espaço também. Por exemplo, veja a mesma tela da Figura 3 quando o aparelho é rotacionamos:
Figura 4: Fundo alterado para a cor azul em tela rotacionada.
Mudar itens de menu em tempo de execução Uma vez que o sistema passou pelo onCreateOptionsMenu, ele não retornará mais a ele, ou seja, uma vez criado o Menu e seus itens, não podemos mais atualizá-los. Pelo menos não com o código atual. Mas o Android não nos deixa na mão. Para Android 2.3 e versões anteriores, o método onCreateOptionsMenu é chamado somente uma vez, como dito anteriormente. Porém, antes desta chamada existe o método onPrepareOptionsMenu, que sempre será chamado. Sendo assim, podemos alterar menus e seus itens neste momento. Veja o exemplo de trecho de código abaixo:
@Override public boolean onPrepareOptionsMenu(Menu menu) { menu.add(0, 1, 1, "Menu " + Math.random()); return true; }
No Android 3.0 e superiores subentende-se que o menu está sempre visível no Action Bar. Então, o onPrepareOptionsMenu só será chamado uma vez. Porém, podemos contornar esta situação chamando o método invalidateOptionsMenu quando desejarmos atualizar nossos itens de menu. Depois disso, o onPrepareOptionsMenu será chamado novamente.
Menu Contextual e Contextual Action Mode O menu contextual serve para mostrar um conjunto de ações que não seja global, ou seja, para toda uma Acitivity, mas sim, para uma determina área da tela, ou, mais comumente mente usada, em uma View. Por exemplo, em uma lista de carros, podemos ter menus globais como “Sobre” e “Sair”. Ao clicar em um item da lista, poderíamos ter as opções “Comprar” e “Cotar”. No Android 2.3 e anteriores, este menu é mostrado como uma caixa de diálogo suspensa, centralizada na tela. Como mostra a Figura 5:
Figura 5: Menu contextual no Android 2.3 AVD.
E como programamos este comportamento? Simples. O primeiro passo é definir qual a View que irá chamar este menu. Para isso, basta chamar o método registerForContextMenu. Veja no trecho de código abaixo:
texto = (TextView) findViewById(R.id.texto); registerForContextMenu(texto);
O próximo passo é sobrescrever o método onCreateContextMenu, que será chamado quando o usuário der um clique longo na View definida anteriormente. Da mesma forma como nos menus tradicionais, também utilizaremos o MenuInflater para recuperar os itens de um XML e jogar diretamente em uma instância de Menu: @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { getMenuInflater().inflate(R.menu.menu_contextual, menu); }
O arquivo de menu segue as mesmas definições apresentadas anteriormente. Apenas mudamos as opções para termos certeza de que nosso exemplo está funcionando. Com esta sequência de código já vamos visualizar o menu da Figura 5, porém, ainda não estamos tratando a ação do usuário. Basta sobrescrevermos o método onContextItemSelected. Este método receberá por parâmetro uma instância de MenuItem, que podemos tratar exatamente da mesma forma como fizemos anteriormente no onOptionsItemSelected.
@Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_amarelo: root.setBackgroundColor(Color.YELLOW); return true; case R.id.menu_branco: root.setBackgroundColor(Color.WHITE); return true; case R.id.menu_preto: root.setBackgroundColor(Color.BLACK); return true; default: return super.onContextItemSelected(item); } }
Contextual Action Mode Mas no Android 3.0 em diante, não é aconselhável utilizar este tipo de menu contextual, mas sim o “Contextual Action Mode”, que substitui os itens do Action Bar por aquelas opções de ação exclusivas de uma View, ou de algum momento/interação ocorrida em sua interface de usuário. Veja na Figura 6 a tela inicial do aplicativo exemplo. Ao darmos o mesmo clique longo do “Hello World”, o Action Bar é substituído pelo contextual action mode, como mostrado na Figura 7. Ao selecionarmos uma das opções de cores, podemos fechar este menu, ou ainda, esperar que o usuário clique no “Done”, localizado na extremidade esquerda. Ou ainda, que o mesmo pressione o botão físico “Back”.
Figura 6: Tela inicial do aplicativo.
Figura 7: Depois de acionar o Contextual Action Mode.
Desta forma estamos seguindo os novos conceitos de UI idealizados com as novas versões do Android. O primeiro passo para trabalhar com o contextual action mode é criar um listener para ouvir a ação de duplo clique de forma programática. E dentro do método onLongClick vamos instanciar uma variável global do tipo ActionMode, chamada de
mActionMode. Perceba que instanciamos está variável chamando o método startActionMode, passando por parâmetro um ActionMode.Callback.
texto.setOnLongClickListener(new View.OnLongClickListener() { public boolean onLongClick(View view) { if (mActionMode != null) { return false; } mActionMode = startActionMode(mActionModeCallback); return true; } });
Mas que é este mActionModeCallback então? Trata-se de uma classe interna que podemos criar:
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { // chamado quando o action mode é criado; através do startActionMode() @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Infla o recurso de menu fornecendo itens de menu contextuais MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_contextual, menu); return true; } // Chamado a cada vez que o action mode é exbido. Sempre chamado após o onCreateActionMode, mas pode ser chamado múltiplas vezes se o modo for invalidado @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; // retorna false se não queremos fazer nada } // Chamado quando o usuário seleciona um menu item @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_amarelo: ... return true; … } } // Chamado quando o usuário sai do action mode @Override public void onDestroyActionMode(ActionMode mode) { mActionMode = null; }
};
O ActionMode.Callback nada mais é do que uma classe que espelha a troca dos estados do action mode, desde o momento que ele é criado até o momento em que ele é retirado da Action Bar. Todos os métodos e classes utilizadas já tinham sido vistos de maneira muito semelhantes, ou iguais, nos trechos de códigos anteriores.
Popup Menu O Popup Menu também foi adicionado na versão 3.0 do Android. Como o nome indica, ele mostrará um menu popup abaixo da View solicitante, caso tenha espaço. Senão, mostrará logo acima. Para testarmos nossas afirmações, vamos colocar um evento de clique simples no botão, chamando um método showPopup quando esta ação ocorrer:
texto.setOnClickListener(new View.OnClickListener() {
});
@Override public void onClick(View v) { showPopup(texto); }
No método showPopup temos o seguinte código:
public void showPopup(View v) { PopupMenu popup = new PopupMenu(this, v); popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.menu_azul: root.setBackgroundColor(Color.BLUE); return true; case R.id.menu_cinza: root.setBackgroundColor(Color.GRAY); return true; case R.id.menu_verde: root.setBackgroundColor(Color.GREEN); return true; }
return false; });
}
MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.activity_main, popup.getMenu()); popup.show(); }
Na primeira linha estamos criando uma instância de PopupMenu, passando um Context e uma View como parâmetros. Depois configuramos um OnMenuItemClickListener, que responderá aos eventos de clique nos itens de menu. Este tratamento já é extensamente conhecido do leitor. Nas últimas três linhas estamos criando um MenuInflater. Inflando o recurso de menu e passando como segundo parâmetro, o menu do popup. E, finalmente, chamamos o método show() de PopupMenu para que o mesmo seja exibido.
Conclusão A API do Android nos permite a criação e gerenciamento de diversos tipos de menu, fornecendo um arsenal completo para que possamos criar aplicativos robustos e de acordo com as melhoras práticas de interface gráfica definida pela comunidade. Percebe-se também uma clara evolução na versão 3.0 em diante. A Action Bar trouxe outro padrão, aumentando consideravelmente o nível de nossas aplicações. Agora basta a você,, desenvolvedor, utilizar a API da melhor maneira possível. Bons códigos.
Sobre Mim Ricardo da Silva Ogliari trabalha com mobilidade desde 2004, tem experiência no desenvolvimento Palm, Java ME, BlackBerry, Android e Windows Phone. Possui mais de 160 publicações entre palestras, workshops e artigos em revistas e sites especializados. Escreve regularmente para as revistas Mobile Magazine e Espírito Livre, além de ser colunista no site da ITWeb, criador e mantenedor do site Mobilidade é Tudo e colunista no site Globalcoders. Trabalhou em grandes empresas do setor, como a Telefônica e o Grupo Pontomobi. Graduado em Ciência da Computação e Especialista em Web: Estratégias de Inovação e Tecnologia. É instrutor na Globalcode e sócioproprietário da StillRocker.