domingo, 12 de julho de 2015

Android - Trabalhando com o DatePicker e TimePicker




Olá amigos do The Club, estou aqui novamente com mais um artigo sobre a plataforma Android. Neste artigo vou explicar e exemplificar o uso dos componentes denominados “Pickers”, traduzindo para o português os “Selecionadores”. Trabalharemos com o “DatePicker”(para selecionar a Data) e o “TimePicker”(para selecionar a Hora) sobrescrevendo e implementando as devidas classes. Pude perceber nesta nova versão do Android algumas melhorias e implementações de novos recursos nestes tipos de controles. Cada “Picker” fornece controles para selecionar parte da Data (dia, mês e ano) ou Hora (hora, minuto e AM/PM). Uma das vantagens do uso destes recursos é que os mesmos nos ajudam a garantir que os usuários possam escolher um formato de data ou hora válido e pré-formatado.  

Classe “DialogFragment”

A principal classe que usaremos é a “DialogFragment”.Esta classe gerencia o ciclo de vida dos “Dialogs”, que nada mais é do que a caixa de diálogo que exibimos flutuando em cima da janela de atividade principal quando instanciamos um “Picker”. Os principais métodos sobrescritos são: OncreateDialog(), OnDateSet(), OnTimeSet() e o Show() . Todos estes métodos serão explicados mais adiante. De acordo com a documentação oficial do Android para Desenvolvedores, a classe “DialogFragment” foi adicionada pela primeira vez para a plataforma no Android 3.0 (API nível 11), ressaltando a compatibilidade dos aplicativo desenvolvidos para versões anteriores, estando disponível na biblioteca de suporte para compatibilidade.

(Importante informar que neste artigo estou utilizando a versão 4.1.2 (API nível 16) do Android, portanto, não foram realizados os testes com versões anteriores descritos acima).

Método OncreateDialog()

Este método permite a personalização da caixa de diálogo. É utilizado para mostrar um “AlerDialog” ao invés de um “Dialog” genérico. Este método é chamado após o evento “OnCreate” e antes do “OnCreateView”. A implementação padrão tem como parâmetro de entrada o último estado da instância salva no Fragmento ou Nulo se o fragmento for recém criado e de retornou ma nova instância de diálogo a ser exibida. Para o nosso artigo iremos retornar a classe “TimerPickerDialog” para Hora e “DatePickerDialog” para Data.

Método OnDateSet() e OnTimeSet()

Método responsável pelo retorno da Data ou Hora selecionada. Possui como parâmetros de entrada os seguintes itens: o componentes em si, o ano, o mês e o dia. Podemos utilizar este método para atualizar algum componente na tela, como por exemplo o “TextView”.

Método Show()

Responsável pela chamada do objeto, sendo que uma das implementações deste método possui como retorno um valor inteiro, que serve para identificar o identificador da transação, se a mesma foi confirmada ou não. Os parâmetros de entrada são: a transação existente e a tag para este fragmento.

Criando o exemplo prático

O nosso exemplo envolverá os dois componentes, o DatePicker e o TimePicker.Para isto descreverei todos os passos daqui pra frente. Inicie uma aplicação do Zero clicando em “File/New/Android Project...” (Não fiz nada de diferente nesta parte)

Criando o “Lay-Out”

O aplicativo possuirá um “RelativeLayout” onde conterá dois “TextViews” e dois “Buttons”. Ver Imagem 01.

Figura 01: Layout.

A Imagem 01 nos dá uma noção do Lay-out.

O XML correspondente (Listagem 01)

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

  <TextView
      android:id="@+id/txtData"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="Data"
      android:textSize="18sp" />

<Button
    android:id="@+id/btnData"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/txtData"
    android:layout_centerHorizontal="true"
    android:text="Escolher uma data"
    android:onClick="MostrarData"/>

<TextView
    android:id="@+id/txtHora"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/btnData"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="18dp"
    android:text="Hora"
    android:textSize="18sp" />

<Button
    android:id="@+id/btnHora"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/btnData"
    android:layout_below="@+id/txtHora"
    android:onClick="MostrarHora"
    android:text="Escolher uma Hora" />

</RelativeLayout>

Listagem 01: XML do Arquivo de layout.

Codificando o exemplo

Possuiremos apenas uma atividade que codificaremos logo em seguida.

Utilizaremos algumas bibliotecas adicionais para desenvolver este exemplo, veja abaixo:

package com.example.artigo_datepicker;

import android.os.Bundle;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentTransaction;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.widget.DatePicker;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import java.util.Calendar;
import android.text.format.DateFormat;
import android.view.View;

As principais são: “DialogFragment”, “FragmentTransaction”,
“TimePickerDialog” e “DatePickerDialog” – ambas utilizadas para formar as classes principais: “DatePickerFragment” e “TimePickerFragment”.

public class MainActivity extends Activity
{
     private TextView txtData, txtHora;
     private int Ano, Mes, Dia, Hora, Minuto;
    
Todas as variáveis serão do tipo “Private” (privadas), sendo txtData e txtHora para armazenar o resultado em um “TextView” e as outras cinco do tipo Inteiras para receber o Ano, Mês, Dia, Hora e Minuto. Foi necessário criar estas variáveis globais pois utilizaremos este resultado várias vezes em nosso aplicativo.

     @Override
     protected void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         InicializaListeners();
    
          final Calendar cal = Calendar.getInstance();
          Ano = cal.get(Calendar.YEAR);
          Mes = cal.get(Calendar.MONTH);
          Dia = cal.get(Calendar.DAY_OF_MONTH);
          Hora = cal.get(Calendar.HOUR);
          Minuto = cal.get(Calendar.MINUTE);

          AtualizarData();
          AtualizarHora();
    }

No evento OnCreate() é onde Inicializaremos nossas variáveis do tipo TextView e com o auxílio da classe “Calendar” recuperamos a Data e Hora Atuais com o método “get”. Esta classe possui as propriedades necessárias para receber os dados. Os procedimentos “AtualizarData()” e “AtualizarHora()” também serão disparados neste momento.(Ambos serão detalhados mais adiante)
    
     public void InicializaListeners()
     {   
        txtData = (TextView) findViewById(R.id.txtData);
        txtHora = (TextView) findViewById(R.id.txtHora);
     }

Método responsável por inicializar as variáveis.
        
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener
    {

É muito comum criarmos classes dentro de classes. Isto fica a cargo do desenvolvedor. Para uma maior simplicidade neste artigo iremos criar e detalhar classes dentro de nossa atividade principal. A Classe “DatePickerFragment” irá herdar da classe principal “DialogFragment”. Irá também implementar os métodos da “DatePickerDialog.OnDateSetListener”.      

         @Override
public Dialog onCreateDialog(Bundle      savedInstanceState)
         {
final Calendar calendario = Calendar.getInstance();
              Ano = calendario.get(Calendar.YEAR);
              Mes = calendario.get(Calendar.MONTH);
              Dia = calendario.get(Calendar.DAY_OF_MONTH);

return new DatePickerDialog(getActivity(), this, Ano, Mes, Dia);
         }

O método “OncreateDialog”, como foi dito anteriormente, ele é responsável pela personalização da caixa de diálogo. Iremos criar uma variável do tipo “Calendar” e ir atribuindo na sequencia nas variáveis inteiras: Ano, Mês e Dia. Este método irá nos retornar a instância configurada e formatada do “DatePickerDialog”.

         @Override
public void onDateSet(DatePicker view, int year, int month, int day)
         {
              Ano = year;
               Mes = month;
               Dia = day;
               AtualizarData();
               MensagemData();
         }
Já o método OnDateSet é disparado no momento que atribuímos alguma modificação no componente. Recebe como parâmetro o próprio DatePicker e as variáveis Ano, Mês e Dia. Dentro dele possuímos outros dois procedimentos. O “AtualizarData”, que nada mais é um método para atualizar a data no componente “txtData” e o “MensagemData” para exibir uma mensagem informativa com a data alterada ao usuário.
        
     @Override
public int show(FragmentTransaction transaction, String tag)
    {            
         return super.show(transaction, tag);
    }

Método principal para chamar o objeto.
    }

    private void AtualizarData()
    {
txtData.setText(new StringBuilder().append(Dia).append("/").append(Mes + 1).append("/").append(Ano).append(" "));
    }

Utilizamos a classe “StringBuilder” para realizar a junção das variáveis Dia, Mês e Ano no formato padronizado e por final atribuímos para a variável “txtData”.
   
    private void MensagemData()
    {
Toast.makeText(this, new StringBuilder().append("Data: ").append(txtData.getText()),  Toast.LENGTH_SHORT).show();
    }

A classe “Toast” dará uma mensagem informativa ao usuário.
    
    public void MostrarData(View v)
    {
DialogFragment ClasseData = new  DatePickerFragment();
ClasseData.show(getFragmentManager(),  "datepicker");
    }

Este é o método que será disparado ao clicar no botão “Escolher uma Data”. Ele instanciará a classe “DatePickerFragment” e invocará o método “Show” com os devidos parâmetros. A Imagem 02 nos dará uma ideia de como está ficando nosso exemplo.
   
 
Figura 02: DatePicker.

Teremos um trabalho identico para trabalharmos com o “TimePicker”. O primeiro passo seria criarmos uma classe para esta tarefa.

public class TimePickerFragment extends DialogFragment implements OnTimeSetListener
    {

A classe TimePickerFragment herdará da mesma “DialogFragment” implementando os métodos da “OnTimeSetListener”.
    @Override
public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        
final Calendar c = Calendar.getInstance();
         Hora = c.get(Calendar.HOUR_OF_DAY);
         Minuto = c.get(Calendar.MINUTE);

return new TimePickerDialog(
              getActivity(),
              this,
              Hora,
              Minuto,
              DateFormat.is24HourFormat(getActivity())
              );
    }
Seguindo a mesma lógica anterior, o método “OnCreateDialog” também irá nos retornar uma caixa de diálogo já configurada e formatada no padrão de Horas. A única diferença é que usaremos a classe “TimePickerDialog” junto com o método “is24HourFormat” que podemos conferir no código acima.

    @Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute)
    {
          Hora = hourOfDay;
           Minuto = minute;
           AtualizarHora();
           MensagemHora();
    }

Faremos o mesmo, criando outros dois procedimentos: o “AtualizarHora” e o “MensagemHora”.

    @Override
public int show(FragmentTransaction transaction, String tag)
    {            
         return super.show(transaction, tag);
    }
Também sobrescrevemos o método “show” (Citado logo no início do artigo).
   
    }
   
    private void AtualizarHora()
    {
txtHora.setText(new StringBuilder().append(Hora).append(":").append(Minuto));
    }
   
Formataremos no formato correto e setamos para a variável “txtHora”.

    private void MensagemHora()
    {
Toast.makeText(this, new StringBuilder().append("Hora: ").append(txtHora.getText()),  Toast.LENGTH_SHORT).show();
    }

Novamente utilizo a classe “Toast” para informar ao usuário.

    public void MostrarHora(View v)
    {
DialogFragment ClasseHora = new TimePickerFragment();
  ClasseHora.show(getFragmentManager(),   "timePicker");
    }

O Método “MostrarHora” será utilizado no evento “Onclick” do botão “Escolher uma Hora”. Neste momento será instanciado a classe “TimePickerFragment” junto com o método “Show”. Ver Imagem 03.
   
   
}



Figura 03: TimePicker.

Conclusões

Procurei neste artigo abordar o uso destes importantes componentes na linguagem Android. Inicialmente procurei familiarizar o leitor com sua principal classe “ DialogFragment” seguindo os principais métodos implementados ao decorrer do artigo. Desenvolvi dois exemplos práticos envolvendo o TimePicker (Horas) e DatePicker (Datas). É importante salientar que com base nestes exemplos podemos criar e personalizar outros recursos da maneira que desejarmos. Vou ficando por aqui, um abraço e até o mês que vem!

Referências

http://developer.android.com/reference/android/widget/DatePicker.html
http://developer.android.com/guide/topics/ui/controls/pickers.html
 

Um comentário: