Nota: aquest article es basa en la versió de Components materials 1.2.0-beta01 com de 1 de juny de 2020 .

En els meus tres anys i mig treballant en un petit equip d’Android a HASHTAGS, una de les coses principals que em motiva a entrar a la feina cada dia és la llibertat i la confiança de la nostra empresa per afrontar un problema de la manera que considerem millor.

La llibertat d’investigar i explorar moltes solucions diferents a un problema que considerem necessari, tot i tenir en compte un període de temps per lliurar les actualitzacions del producte, ens permet trobar la millor solució tant per als nostres clients com per al nostre programari.



Un d’aquests desafiaments consistia en la creació d’un component d’interfície d’usuari per a la nova funció d’informes mòbils. Aquest nou component era un selector de mesos, que permetia als nostres usuaris abastar un interval de dates per a un informe d’anàlisi.

El lloc de sortida que vam triar va ser l’existent Biblioteca de components materials . En lloc de començar de zero, aquesta biblioteca es manté activament i s’alinea amb les especificacions del material. Amb aquesta biblioteca com a fonament, probablement podríem reduir la quantitat de lògica que hauríem d’escriure nosaltres mateixos.

En aquest article, parlaré de com hem abordat aquest procés, alguns factors únics en la creació de l’aplicació Sprout per a Android, alguns “gotchas” que van aparèixer (i es van solucionar) al llarg del camí i què saber si treballant en un projecte similar.

Introducció

Els components materials d'Android 1.1.0 Alliberament ha introduït un nou component d’interfície d’usuari Data Picker. Una de les addicions benvingudes d’aquest nou MaterialDatePicker a través de l'AppCompat CalendarView és la possibilitat de seleccionar un interval de dates mitjançant una vista de calendari o un camp d’entrada de text.

L’antic AppCompat CalendarView no era molt flexible. Va ser un bon component per al cas d’ús limitat que s’havia de resoldre; és a dir, seleccionar una data única i unes dates mínimes i màximes opcionals per especificar un interval de dates permès.

El nou MaterialDatePicker es va construir amb més flexibilitat per permetre l’ús de funcionalitats ampliades de comportament. Funciona a través d'una sèrie d'interfícies que es podrien implementar per ajustar i modificar el comportament del selector.

Aquesta modificació del comportament es realitza en temps d'execució mitjançant un conjunt de funcions de patró del constructor a MaterialDatePicker.Builder classe.

Això significa que som capaços d'ampliar el comportament base d'aquest MaterialDatePicker mitjançant components d’interfície composable.

Nota: Tot i que hi ha diversos components diferents, el MaterialDatePicker utilitza, en aquest article tractarem només el component de selecció de dates.

Selector d'interval de dates

L’equip d’Android de HASHTAGS estava creant la nostra secció d’informes d’Analytics.

Aquesta nova secció permetria als nostres usuaris seleccionar un conjunt de filtres i un conjunt d’intervals de dates que inclouria l’informe.

El MaterialDatePicker venia amb alguns components pre-construïts que podríem aprofitar per aconseguir el nostre cas d'ús.

Per al nostre cas més comú, que permet a un usuari seleccionar un interval de dates, la predefinida MaterialDatePicker n’hi hauria prou:

Amb aquest bloc de codi, obtenim un selector de dates que permet als usuaris seleccionar un interval de dates.

Selector de dates mensuals

Un dels informes de HASHTAGS que té una selecció de dates més única és el Twitter Trends Report.

Aquest informe difereix dels altres en què, en lloc de permetre qualsevol tipus d’interval de dates, imposa una selecció d’un sol mes, cosa que significa que un usuari només pot seleccionar març 2020 contra el 3 de març al 16 de març de 2020.

La nostra aplicació web ho gestiona mitjançant un camp de formulari desplegable:

El MaterialDatePicker no té cap manera d’aplicar aquesta restricció amb el selector d’intervals de dates de materials preconstruït que hem comentat a la secció anterior. Afortunadament, MaterialDatePicker es va construir amb parts composables que ens permeten ampliar el comportament predeterminat per al nostre cas d’ús particular.

Comportament de la selecció de dates

El MaterialDatePicker aprofita un DateSelector com a interfície utilitzada per a la lògica de selecció del selector.

Des del Javadoc:

“Interfície per a usuaris de {@link MaterialCalendar} per controlar com el calendari mostra i retorna les seleccions ... ”

Notareu que el MaterialDatePicker.Builder.dateRangePicker() retorna una instància del constructor de RangeDateSelector, que hem utilitzat a l'exemple anterior.

Aquesta classe és un selector predefinit que implementa DateSelector.

Pluja d’idees sobre un comportament mensual de selecció de dates

Per al nostre cas d'ús, volíem una manera de fer que els nostres usuaris seleccionessin un mes sencer com a interval de dates seleccionat; per exemple. Maig 2020, abril 2020, etc.

Vam pensar que el pre-construït RangeDateSelector a la qual es fa referència anteriorment ens va arribar fins a la major part del camí. El component permetia a un usuari seleccionar un interval de dates i aplicar un lligat .

L'únic que faltava era una manera d'aplicar una selecció per seleccionar automàticament tot el mes. El comportament predeterminat de RangeDateSelector fa que l'usuari seleccioni una data d'inici i una data de finalització.

Volíem un comportament de manera que quan un usuari seleccionés un dia del mes, el selector seleccionaria automàticament tot el mes com a interval de dates.

La solució que vam decidir va ser ampliar el RangeDateSelector i, a continuació, anul·leu el comportament de la selecció del dia per seleccionar automàticament tot el mes.

Per sort, hi ha una funció que podem anul·lar des de la interfície DateSelector anomenat: select(selection: Long).

Aquesta funció s'invocarà quan un usuari selecciona un dia al selector, amb el dia seleccionat passat en mil·lisegons UTC de l'època.

Implementació d’un comportament mensual de selecció de dates

La implementació va resultar ser la part més senzilla, ja que tenim una funció clara que podem anul·lar per obtenir el comportament que volem.

La lògica bàsica serà aquesta:

  1. L'usuari selecciona un dia.
  2. El select() La funció s'invoca amb el dia seleccionat a Llarg Mil·lisegons UTC de l'època.
  3. Cerqueu el primer i l'últim dia del mes del dia que ens va passar.
  4. Feu una trucada a super.select(1st of month) & super.select(last day of month)
  5. El comportament dels pares de RangeDateSelector hauria de funcionar com s'esperava i seleccionar el mes com a interval de dates.

Unint-ho tot

Ara que tenim el nostre Custom MonthRangeDateSelector, podem configurar el nostre MaterialDatePicker.

Per portar l'exemple més enllà, podem processar el resultat de la selecció així:

El resultat serà així:

Gotchas

Només hi havia un problema important que dificultava l’arribada a aquesta solució.

Els components principals que s’utilitzen per construir el nostre MonthRangeDateSelector eren la classe RangeDateSelector i la interfície DateSelector. La versió de la biblioteca utilitzada en aquest article (1.2.0-beta01) restringia la visibilitat d'aquests dos fitxers per dissuadir la seva ampliació o implementació.

Com a resultat, tot i que vam poder compilar amb èxit el nostre nou MonthRangeDateSelector, el compilador va mostrar una advertència molt aterridora per desanimar-nos a fer-ho:

Una manera d’ocultar aquest advertiment del compilador és afegir un @Suppress('RestrictedApi') així:

Aquesta experiència il·lustra com, tot i que la Biblioteca de components de materials ha proporcionat components nous i fantàstics a la comunitat de desenvolupadors d'Android, encara és un treball en curs.


com tornar a publicar una foto d’Instagram

Una gran part d’aquesta biblioteca és l’obertura als comentaris de la comunitat Android. Després de descobrir aquesta restricció de visibilitat del component, vaig obrir un fitxer assumpte al Projecte Github i fins i tot va obrir un fitxer PR per abordar-ho de seguida.

Aquest bucle de retroalimentació obert entre l'equip de components materials i la comunitat d'Android genera una gran col·laboració i resultats per a tothom.

Conclusió

El nou MaterialDatePicker té algunes funcions excel·lents, que probablement cobriran la majoria de casos d’ús de la selecció de dates.

Tanmateix, la millor part d’ell com AppCompat CalendarView és que està construït de forma composable. Per tant, es pot ampliar i modificar fàcilment per a casos d'ús específics, mentre que seria molt més difícil aconseguir aquestes coses a CalendarView.

Especial agraïment

M'agradaria destacar algunes persones que van ajudar a revisar per pares aquest article: