Alex é instrutor e desenvolvedor e possui experiência em Java, Kotlin, Android. Atualmente cria conteúdo no canal https://www.youtube.com/@AlexFelipeDev.
Inscreva-se em nossa Newsletter
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
Na implementação do App, temos um RecyclerView que apresenta cada evento cadastrado. Para cadastrar o evento, clicamos no FAB (FloatingActionButton), preenchemos o formulário com título e data e clicamos em Salvar.
O grande detalhe da implementação, é que o usuário é responsável em escrever a data com o formato esperado, o que pode ocasionar em dúvidas ou frustrações...
No caso desta implementação, um formato inesperado quebra o App! Uma das piores experiências para o usuário... Sendo assim, precisamos evitar ao máximo esse comportamento e podemos considerar as seguintes técnicas na regra de negócio:
Implementar validações para orientar o formato correto para o usuário.
Ambas as técnicas são comuns na maioria das linguagens, porém, dado que estamos no ambiente Android, podemos também utilizar um componente que auxilie na parte visual, o MaterialDatePicker:
Adicionando os componentes do Material Design
Para utilizar o MaterialDatePicker, o projeto precisa da dependência dos componentes do Material Design:
dependencies {
// outras dependências
implementation 'com.google.android.material:material:1.3.0'
}
O projeto fornecido já tem a dependência configurada!
Após sincronizar, temos acesso ao MaterialDatePicker.
Criando o MaterialDatePicker
Para utilizar o MaterialDatePicker, temos uma abordagem similar ao AlertDialog, ou seja, um builder para nos auxiliar:
Com apenas esse código, o usuário é capaz de selecionar a data desejada e confirmar. Porém, o código não é o suficiente para obtermos a data selecionada.
Pegando a data do MaterialDatePicker
Para pegar a data selecionada do MaterialDatePicker, precisamos adicionar um listener no dialog com a função addOnPositiveButtonClickListener() que recebe uma expressão lambda com o valor da data em milisegundos:
A partir do valor em milisegundos, podemos converter para uma data com uma API disponível, como por exemplo, as classes do pacote java.time que oferece a Instant capaz de fazer isso:
Basicamente, criamos uma instância de Instant por meio dos milisegundos, então configuramos o time zone da America São Paulo com deslocamento em UTC e convertemos para a API LocalDate que facilita o trabalho de datas...
Depois de todo esse código assustador para fazer uma conversão, temos a data esperada:
2021-02-23 11:44:20.465 17940-17940/br.com.alura.eventos I/MaterialDatePicker: data com LocalDate:2021-02-23
Com a data pronta, precisamos integrar a nossa solução com o fluxo do App.
Adicionado o MaterialDatePicker no formulário
No formulário, precisamos chamar o MaterialDatePicker ao clicar no campo de data, portanto, podemos adicionar todo o nosso código dentro do listener de clique do campo de data:
Note que ao mover o código, precisamos também adicionar o FragmentManager como parâmetro do método show() da FormEventoDialog. Na Activity, no listener do FAB, precisamos também enviar o FragmentManager como argumento:
Esse código é o suficiente para testar o App e abrir o MaterialDatePicker clicando no campo de data.
Por mais que funcione, a experiência do usuário não é bacana, pois precisamos de um segundo clique após focar no campo de data para apresentar o MaterialDatePicker!
Melhorando a experiência de clique no campo de data
Para evitar esse comportamento, modificamos o TextInputEditText para que não seja focável:
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"><!-- restante do layout --><com.google.android.material.textfield.TextInputEditTextandroid:id="@+id/data"android:layout_width="match_parent"android:layout_height="wrap_content"android:focusable="false"android:hint="Data" /></androidx.constraintlayout.widget.ConstraintLayout>
Em seguida, precisamos pegar a data selecionada e preencher o campo assim que o usuário confirma:
Observe que funciona, porém, ao salvar a nota nesse padrão, temos o mesmo problema de quebrar o App, pois a configuração do padrão esperado é dd/MM/yyyy, ou seja, 23/02/2021 considerando esse exemplo.
Formatando data
Para formatar a data com um padrão diferente, podemos utilizar as APIs do próprio java.time também, a DateTimeFormatter:
val formatador = DateTimeFormatter
.ofPattern("dd/MM/yyyy", Locale("pt-br"))
val dataFormatada = formatador.format(data)
binding.data.setText(dataFormatada)
E temos este resultado ao fazer o mesmo teste:
E agora podemos salvar sem problema algum:
Utilizando funções de extensão de LocalDate
Depois de finalizar a implementação, podemos simplificar a nossa solução utilizando algumas funções de extensão já adicionadas no projeto: