Tutorial Android 4 #8 – Utilizando Abas

Padrão

Olá pessoal! No último post da série, adicionamos uma listagem com os contatos adicionados, mostrando um ícone indicando o tipo de contato, além do seu respectivo endereço. Hoje vamos separar a listagem do formulário, colocando uma aba para cada um.

O primeiro passo é modificar o nosso arquivo de layout activity_meus_contatos.xml, retirando o LinearLayout e adicionando os itens TabHostTabWidget e FrameLayout, que acomodarão nossos itens. Assim, o nosso novo arquivo activity_meus_contatos.xml ficará assim:

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tabhost"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <ListView
                android:id="@+id/contatos"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <RelativeLayout
                android:id="@+id/detalhes"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" >

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:orientation="vertical" >

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/nome" />

                    <EditText
                        android:id="@+id/nome"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:inputType="text" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/email" />

                    <EditText
                        android:id="@+id/email"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:inputType="textEmailAddress" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/tipo_contato" />

                    <RadioGroup
                        android:id="@+id/tipo_contato"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content" >

                        <RadioButton
                            android:id="@+id/pessoal"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="@string/tipo_pessoal" />

                        <RadioButton
                            android:id="@+id/profissional"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="@string/tipo_profissional" />

                        <RadioButton
                            android:id="@+id/academico"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="@string/tipo_academico" />
                    </RadioGroup>
                </LinearLayout>

                <Button
                    android:id="@+id/salvar"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:text="@string/salvar" />
            </RelativeLayout>
        </FrameLayout>
    </LinearLayout>

</TabHost>

O único detalhe que podemos salientar sobre esse novo layout, é o atributo identificador nos nós relativos às abas.

@android:id/tabhost@android:id/tabs e @android:id/tabcontent referem-se aos elementos chaves do layout de abas, que possuem tais nomes internamente no Android. Assim, precisamos colocar esses ids para que o layout seja montado corretamente (e por esse motivo não podemos alterar seus identificadores).

O próximo passo é modificar o nosso o método onCreate da classe MeusContatos para carregar o layout de abas e dividir o conteúdo entre elas. Carregamos o nosso TabHost e, a partir dele, criamos as outras abas programaticamente. Adicione o seguinte código logo após a chamada ao setContentView().

TabHost abas = (TabHost) findViewById(R.id.tabhost);
abas.setup();

TabSpec descritor = abas.newTabSpec("aba1");
descritor.setContent(R.id.contatos);
descritor.setIndicator(getString(R.string.contatos));
abas.addTab(descritor);

descritor = abas.newTabSpec("aba2");
descritor.setContent(R.id.detalhes);
descritor.setIndicator(getString(R.string.detalhes));
abas.addTab(descritor);

Criamos, então, duas abas, uma com o título de Contatos e a outra com o título de Detalhes. Ah, lembrem-se de criar as duas strings lá no nosso arquivo strings.xml! Isso para, posteriormente, podermos facilmente internacionalizar nosso aplicativo 🙂

Se executarmos neste momento nosso aplicativo, ele já terá o visual que desejamos:

tutorial-android-01tutorial-android-02

Continuando, precisamos adicionar uma forma de que, quando o usuário tocar sobre um dos contatos da lista, ele possa editar suas informações no formulário. Para isso, vamos criar fazer a nossa classe implementar mais um listener, o OnItemClickListener, para que tenhamos um feedback para esse evento, possibilitando manipulá-lo e realizar as tarefas necessárias. Portanto, vamos fazer a nossa classe implementar tal listener e vamos implementar o método que a interface exige.

public class MeusContatos extends Activity implements OnClickListener, OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}

Agora, vamos adicionar a nossa classe como listener da lista.

lista.setOnItemClickListener(this);

Por organização, vamos fazer uma separação dos elementos de interface, colocando-os como atributos da nossa classe. Isso nos ajudará a deixá-la mais organizada e facilitará a implementação da funcionalidade de editar um registro ao clicar em um item da lista. Dessa forma, vamos adicionar os quatro elementos assim:

private List<Contato> contatos = new ArrayList<Contato>();
private ContatoAdapter adaptador = null;

private TabHost abas = null;
private EditText nome = null;
private EditText email = null;
private RadioGroup tipoContato = null;
private Button salvar = null;

Em seguida, vamos editar o método onCreate() para que inicialize estas variáveis para nós.

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_meus_contatos);

	abas = (TabHost) findViewById(R.id.tabhost);
	abas.setup();

	TabSpec descritor = abas.newTabSpec("aba1");
	descritor.setContent(R.id.contatos);
	descritor.setIndicator(getString(R.string.contatos));
	abas.addTab(descritor);

	descritor = abas.newTabSpec("aba2");
	descritor.setContent(R.id.detalhes);
	descritor.setIndicator(getString(R.string.detalhes));
	abas.addTab(descritor);

	salvar = (Button) findViewById(R.id.salvar);
	salvar.setOnClickListener(this);

	nome = (EditText) findViewById(R.id.nome);
	email = (EditText) findViewById(R.id.email);

	tipoContato = (RadioGroup) findViewById(R.id.tipo_contato);

	ListView lista = (ListView) findViewById(R.id.contatos);
	adaptador = new ContatoAdapter();
	lista.setAdapter(adaptador);
	lista.setOnItemClickListener(this);
}

Como transferimos a inicialização dos componentes para o método onCreate(), podemos retirá-la do método onClick(), deixando-o mais leve:

@Override
public void onClick(View v) {
	Contato contato = new Contato();
	contato.setNome(nome.getText().toString());
	contato.setEmail(email.getText().toString());

	switch (tipoContato.getCheckedRadioButtonId()) {
	case R.id.pessoal:
		contato.setTipo(Contato.Tipo.PESSOAL);
		break;
	case R.id.profissional:
		contato.setTipo(Contato.Tipo.PROFISSIONAL);
		break;
	case R.id.academico:
		contato.setTipo(Contato.Tipo.ACADEMICO);
		break;
	}

	adaptador.add(contato);
}

Vamos, então adicionar a implementação do método onItemClick(), para atualizar o formulário com base nos dados do item clicado.

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
	Contato c = contatos.get(position);
	nome.setText(c.getNome());
	email.setText(c.getEmail());

	switch (c.getTipo()) {
	case ACADEMICO:
		tipoContato.check(R.id.academico);
		break;
	case PESSOAL:
		tipoContato.check(R.id.pessoal);
		break;
	case PROFISSIONAL:
		tipoContato.check(R.id.profissional);
		break;
	}

	abas.setCurrentTab(1);
}

Neste método simplesmente obtemos o objeto do tipo Contato que foi clicado e injetamos seus dados nos elementos da tela, mudando para a aba do formulário logo em seguida.

Por fim, vamos fazer um pequeno ajuste no método onClick(), para que ele limpe o formulário e mude para a listagem ao se salvar o contato. Para auxiliar, vamos criar um método limparFormulario() para facilitar o entendimento do código:

@Override
public void onClick(View v) {
	Contato contato = new Contato();
	contato.setNome(nome.getText().toString());
	contato.setEmail(email.getText().toString());

	switch (tipoContato.getCheckedRadioButtonId()) {
	case R.id.pessoal:
		contato.setTipo(Contato.Tipo.PESSOAL);
		break;
	case R.id.profissional:
		contato.setTipo(Contato.Tipo.PROFISSIONAL);
		break;
	case R.id.academico:
		contato.setTipo(Contato.Tipo.ACADEMICO);
		break;
	}

	adaptador.add(contato);

	abas.setCurrentTab(0);
	limparFormulario();
}

private void limparFormulario() {
	nome.setText("");
	email.setText("");
	tipoContato.check(0);
}

E é isso! Nosso sistema tem um pequeno bug de duplicar o contato ao editá-lo, mas fiquem tranquilos pois vamos corrigi-lo logo logo! 🙂

Pra quem precisar, pode baixar o código do projeto aqui. Até a próxima!