Criando um Navigation Drawer customizado no Android

Padrão

Olá pessoal! Voltando a postar aqui no blog, hoje vamos ver como criar um Navigation Drawer customizado no Android. Navigation Drawer, pra quem não sabe, é aquele menuzinho deslizante no Android que vem do lado esquerdo do app, sinalizado pelos três traços horizontais ao lado do ícone do aplicativo na Action Bar.

Captura de tela 2014-06-24 20.06.17

Nas últimas versões do Android Studio, nós já temos um modelo de Activity que cria um Navigation Drawer pra gente, um modelo simplezinho com uma lista de opções. Nesse post, vamos ver como criar um Navigation Drawer com uma View customizada e fazer aquele visual bacana pro seu app.

Pra início de conversa, crie um projeto no seu Android Studio (estou utilizando para esse post a versão 0.6.1) e utilize o modelo de Activity com o Navigation Drawer.

Captura de tela 2014-06-24 20.12.13

Ao criar uma Activity com esse modelo, uma porção de código é gerada (classes e XMLs de layout). Vamos analisar alguns pontos principais.

  • Activity: Simplificadamente, possui como layout um DrawerLayout (para o efeito de deslize do Navigation Drawer), tendo como filhos o Fragment do Navigation Drawer e um FrameLayout onde o conteúdo das telas será colocado. Já no código, o ponto mais importante é o método onNavigationDrawerItemSelected(), método de callback chamado toda vez que um elemento do drawer é selecionado.
  • NavigationDrawerFragment: a classe que representa o nosso drawer. No wizard é gerada uma tonelada de código, mas podemos destacar o método onCreateView() no qual criamos o layout do drawer e o método selectItem(), responsável por notificar o que foi selecionado nele.

Nesse código gerado, temos um fragment chamado PlaceholderFragment, utilizado apenas para criar o efeito de mudança nas opções. Além disso, o layout do drawer é simplesmente uma lista semi-transparente.

Captura de tela 2014-06-24 21.12.45

Para este exemplo, então, vamos criar um Navigation Drawer mais interessante, com um cabeçalho para um resumo de um perfil de usuário (fictício), vamos deixar essas três opções de navegação que já estão ali (ou mesmo podemos adicionar mais algumas) e um rodapé para créditos de desenvolvimento. Além disso, vamos fazer com que o Navigation Drawer mantenha destacada a página de navegação atual do usuário.

Vamos lá. O primeiro passo é modificarmos o arquivo de layout do Navigation Drawer, no caso, o arquivo fragment_navigation_drawer.xml. Adicionei um RelativeLayout ao redor da lista e a configurei para ficar entre o TextView de topo (perfil do usuário) e rodapé (créditos). Ficou assim:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    tools:context="net.rafaeltoledo.hellospringapi.NavigationDrawerFragment">

    <TextView
        android:id="@+id/headerView"
        style="?android:attr/textAppearanceLarge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"        
        android:drawableLeft="@drawable/photo"
        android:gravity="center_vertical"
        android:padding="25dp"
        android:text="Rafael Toledo" />

    <TextView
        android:id="@+id/footerView"
        style="?android:attr/textAppearanceMedium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"        
        android:gravity="center"
        android:padding="20dp"
        android:text="Desenvolvido por Rafael Toledo"
        android:textStyle="bold" />

    <ListView
        android:id="@+id/navigationItems"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/footerView"
        android:layout_below="@+id/headerView"
        android:background="#cccc"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />

</RelativeLayout>

O próximo passo é modificarmos a forma como o NavigationDrawerFragment lida com seu layout (já que anteriormente ele o tratava apenas como uma lista). Vamos fazer uma leve modificação no método onCreateView() para que ele busque a lista no layout. Fica assim:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(
            R.layout.fragment_navigation_drawer, container, false);

    mDrawerListView = (ListView) view.findViewById(R.id.navigationItems);
    mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    });
    mDrawerListView.setAdapter(new ArrayAdapter<String>(
            getActionBar().getThemedContext(),
            android.R.layout.simple_list_item_activated_1,
            android.R.id.text1,
            new String[]{
                    getString(R.string.title_section1),
                    getString(R.string.title_section2),
                    getString(R.string.title_section3),
            }));
    mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
    return view;
}

Veja que não modificamos muita coisa. Só fizemos alguns ajustes devido ao fato de que o elemento raiz do layout do drawer não é mais a lista e sim o RelativeLayout. Dessa forma, precisamos fazer o lookout nele pra buscar a lista. Se executarmos o app nesse ponto, teremos algo assim:

Captura de tela 2014-06-24 21.30.59

Percebam que o conteúdo está um pouco “espremido” no Navigation Drawer devido a sua largura. Segundo as boas práticas de design do Android, um Navigation Drawer pode ter entre 240dp 320dp. Vamos alterar a sua largura no arquivo values/dimens.xml para 300dp, alterando o valor de navigation_drawer_width.

Captura de tela 2014-06-24 21.35.23

Já ficou mais interessante, né? O negócio agora é fazermos as opções serem, de fato, selecionadas quando forem clicadas, ficando fácil pro usuário saber em qual tela ele está. Pra isso, basta fazermos uma pequena modificação no método onCreateView() do NavigationDrawerFragment, alterando o layout do adapter de simple_list_item_1 para simple_list_item_activated_1. Simples não?

Captura de tela 2014-06-24 22.06.59

E é isso minha gente! Ah, é bom ficar atento que esse último passo não funciona no Android 2.3! Se bem que, hoje, pra um app novo, já não compensa (na minha opinião) suportar o Gingerbread… Bola pra frente devs!

Até a próxima!

8 comentários sobre “Criando um Navigation Drawer customizado no Android

  1. Mauro

    Rafael, obrigado pelo seu Blog… tem me ajudado bastante a começar a programar em Android. Sou prog. C# a um tempo e estou migrando “a força” para conseguir completar 2 projetos mobile….

    O fato é que esse seu exemplo era tudo o que eu precisava, mas, está dando um erro, dizendo:

    Tem como vc colocar o fonte desse projeto em algum canto para que eu possa baixar e ve-lo rodando? E/ou você me ajudar entender o que tem de errado no meu proj?

    Aguardo e obrigado!!!

  2. rafaelkowal

    Estou atrás de como adicionar icones utilizando o Navigation Drawer, o tutorial está muito bom só faltou os icones. Valew!!!

  3. Guilherme De Carvalho Carneiro

    Rafael boa tarde.

    Estou utilizando o Drawer com o ListView com itens que o usuário poderá escolher gostaria de saber como eu faço para “fechar” o drawer quando o usuário clicar num dos itens da ListView.

  4. Marcelo M. Mesquita

    Rafael, estou com um problema, iniciei uma activity como opção ao primeiro item da lista. Funciona ok quando acionada e retornada através do encerramento da activity, ok! O problema está no seguinte: ao acionar a nova activity, rotacioná-la (landscape) e a encerrar, a activity volta para a activity anterior com a Navigation Drawer aberta, e não consigo fazer com que o retorno se dê com a Navigation fechada, como é o caso quando não rotaciono a tela. Pode me ajudar?

    • Ederson Duarte Itabaiana junior

      pesquise sobre o método:
      @Override
      protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);

      // outState envia a informação para capturar depois da rotação
      // ouState.putString(“informação”)
      }

      e tente capturar a informação no onCreateBundle

  5. Rafael Moralles

    Opa Rafael beleza?

    Muito obrigado pelo tutorial, me ajudou demais na minha aplicação.
    Muito legal também a tua palestra no TDC POA.

    Abraço

Deixe uma resposta