Nota: Este artigo foi baseado na versão de Componentes de Material 1.2.0-beta01 a partir de 1 de junho de 2020 .



Em meus três anos e meio de trabalho em uma pequena equipe Android na HASHTAGS, uma das principais coisas que me motivam a ir para o trabalho todos os dias é a liberdade e a confiança de nossa empresa para resolver um problema da maneira que acharmos melhor.



A liberdade de pesquisar e explorar muitas soluções diferentes para um problema que consideramos necessário, ao mesmo tempo em que consideramos um prazo para entregar as atualizações do produto, nos permite encontrar a melhor solução para nossos clientes e nosso software.

Um desses desafios envolveu a construção de um componente de IU para nosso novo recurso Mobile Reporting. Este novo componente era um selecionador de mês, que permitia aos nossos usuários definir um intervalo de datas para um relatório analítico.

O ponto de partida que escolhemos foi o existente Biblioteca de Componentes de Materiais . Em vez de começar do zero, esta biblioteca é mantida ativamente e se alinha com as especificações de materiais. Com esta biblioteca como base, provavelmente poderíamos reduzir a quantidade de lógica que teríamos que escrever.

Neste artigo, irei abordar como abordamos esse processo, alguns fatores exclusivos na construção do aplicativo Sprout para Android, algumas 'pegadinhas' que surgiram (e foram corrigidas) ao longo do caminho e o que saber se você trabalhando em um projeto semelhante.

Introdução

Os componentes materiais do Android 1.1.0 Release introduziu um novo componente de IU do selecionador de data. Uma das adições bem-vindas deste novo MaterialDatePicker sobre o AppCompat CalendarView é a capacidade de selecionar um intervalo de datas usando uma visualização de calendário ou um campo de entrada de texto.



O antigo AppCompat CalendarView não era muito flexível. Era um bom componente para o caso de uso limitado que pretendia resolver; ou seja, selecionar uma única data e datas mínimas e máximas opcionais para especificar um limite de intervalo de datas permitido.

O novo MaterialDatePicker foi construído com mais flexibilidade para permitir o uso de funcionalidade expandida de comportamento. Ele funciona por meio de uma série de interfaces que podem ser implementadas para ajustar e modificar o comportamento do selecionador.

Essa modificação de comportamento é feita em tempo de execução por meio de um conjunto de funções de padrão do construtor no MaterialDatePicker.Builder aula.



Isso significa que podemos estender o comportamento básico deste MaterialDatePicker por meio de componentes de interface combináveis.

Observação: embora haja vários componentes diferentes, o MaterialDatePicker utiliza, neste artigo abordaremos apenas o Componente de Seleção de Data.


número bíblico 5

Selecionador de intervalo de datas

A equipe do HASHTAGS Android estava em processo de construção de nossa seção de relatórios analíticos.

Essa nova seção permitiria aos nossos usuários selecionar um conjunto de filtros e um conjunto de intervalos de datas que o relatório cobriria.

O MaterialDatePicker veio com alguns componentes pré-construídos que poderíamos aproveitar para realizar nosso caso de uso.

Para nosso caso mais comum, permitir que um usuário selecione um intervalo de datas, o MaterialDatePicker bastaria:

Com este bloco de código, obtemos um selecionador de data que permite aos usuários selecionar um intervalo de datas.

Selecionador de data mensal

Um dos relatórios HASHTAGS que tem uma seleção de data mais exclusiva é o Twitter Trends Report.

Este relatório difere dos outros porque, em vez de permitir qualquer tipo de intervalo de datas, ele impõe uma única seleção de mês, o que significa que um usuário só pode selecionar março de 2020 versus 3 de março a 16 de março de 2020.

Nosso aplicativo da web lida com isso usando um campo de formulário suspenso:

O MaterialDatePicker não tem uma maneira de impor tal restrição com o Seletor de intervalo de datas de material predefinido discutido na seção anterior. Felizmente, o MaterialDatePicker foi construído com partes combináveis ​​que nos permitem expandir o comportamento padrão para nosso caso de uso específico.

Comportamento de seleção de data

O MaterialDatePicker alavanca um DateSelector como a interface usada para a lógica de seleção do selecionador.

Do Javadoc:

“Interface para usuários de {@link MaterialCalendar} para controlar como o Calendário exibe e retorna as seleções ... ”

Você notará que MaterialDatePicker.Builder.dateRangePicker() retorna uma instância do construtor de RangeDateSelector, que usamos no exemplo acima.

Esta classe é um seletor predefinido que implementa DateSelector.

Brainstorming de um comportamento de seleção de data mensal

Para nosso caso de uso, queríamos uma maneira de fazer com que nossos usuários selecionassem um mês inteiro como um intervalo de datas selecionado; por exemplo. Maio de 2020, abril de 2020, etc.

Pensamos que o pré-construído RangeDateSelector referenciado acima nos levou a maior parte do caminho. O componente permitia que um usuário selecionasse um intervalo de datas e aplicasse um vinculado .

A única coisa que faltava era uma maneira de forçar uma seleção para selecionar automaticamente o mês inteiro. O comportamento padrão de RangeDateSelector faz com que o usuário selecione uma data de início e uma data de término.

Queríamos um comportamento que, quando um usuário seleciona um dia do mês, o selecionador seleciona automaticamente o mês inteiro como o período.

A solução que decidimos foi estender o RangeDateSelector e, em seguida, substitua o comportamento de seleção do dia para selecionar automaticamente o mês inteiro.

Felizmente, existe uma função que podemos substituir na interface DateSelector chamado: select(selection: Long).

Essa função será chamada quando um usuário selecionar um dia no seletor, com o dia selecionado passado em milissegundos UTC da época.

Implementando um comportamento de seleção de data mensal

A implementação acabou sendo a parte mais simples, já que temos uma função clara que podemos substituir para obter o comportamento que desejamos.

A lógica básica será esta:

  1. O usuário seleciona um dia.
  2. O select() função é invocada com o dia selecionado em um Longo UTC milissegundos da época.
  3. Encontre o primeiro e o último dia do mês a partir de um determinado dia passado para nós.
  4. Faça uma chamada para super.select(1st of month) & super.select(last day of month)
  5. O comportamento pai de RangeDateSelector deve funcionar conforme o esperado e selecione o mês como um intervalo de datas.

Juntando tudo

Agora que temos nosso Custom MonthRangeDateSelector, podemos configurar nosso MaterialDatePicker.

Para levar o exemplo adiante, podemos processar o resultado da seleção assim:

O resultado será assim:

Pegadinhas

Havia apenas um problema importante que tornava difícil chegar a essa solução.

Os principais componentes usados ​​para construir nosso MonthRangeDateSelector onde a classe RangeDateSelector e a interface DateSelector. A versão da biblioteca usada neste artigo (1.2.0-beta01) restringiu a visibilidade desses dois arquivos, para desencorajar sua extensão ou implementação.

Como resultado, embora pudéssemos compilar com sucesso nosso novo MonthRangeDateSelector, o compilador mostrou um aviso muito assustador para nos desencorajar de fazê-lo:

Uma maneira de ocultar este aviso do compilador é adicionar um @Suppress('RestrictedApi') igual a:

Esta experiência ilustra como, embora a Biblioteca de componentes de materiais tenha fornecido alguns novos componentes excelentes para a comunidade de desenvolvedores Android, ainda é um trabalho em andamento.

Uma grande parte desta biblioteca é a abertura para feedback da comunidade Android! Depois de descobrir essa restrição de visibilidade do componente, abri um emitir no Projeto Github, e até abriu um PR para resolver isso imediatamente.

Esse ciclo de feedback aberto entre a equipe de componentes materiais e a comunidade Android gera grande colaboração e resultados para todos.

Conclusão

O novo MaterialDatePicker tem algumas funcionalidades prontas para usar que provavelmente cobrirão a maioria dos casos de uso de seleção de data.

No entanto, a melhor parte disso em relação a algo como AppCompat CalendarView é que ele é construído de forma combinável. Portanto, ele pode ser facilmente estendido e modificado para casos de uso específicos, embora seja muito mais difícil realizar essas coisas no CalendarView.

Agradecimentos especiais

Eu gostaria de destacar algumas pessoas que ajudaram a revisar este artigo:

Compartilhe Com Os Seus Amigos: