Remarque: cet article était basé sur la version des composants matériels 1.2.0-beta01 à partir de 1 juin 2020 .



Au cours de mes trois ans et demi de travail dans une petite équipe Android chez HASHTAGS, l'une des principales choses qui me motive à venir travailler chaque jour est la liberté et la confiance de notre entreprise pour s'attaquer à un problème de la manière que nous jugeons la meilleure.



La liberté de rechercher et d'explorer de nombreuses solutions différentes à un problème que nous jugeons nécessaire, tout en tenant compte d'un délai de mise à jour des produits, nous permet de trouver la meilleure solution pour nos clients et nos logiciels.

L'un de ces défis consistait à créer un composant d'interface utilisateur pour notre nouvelle fonctionnalité de rapport mobile. Ce nouveau composant était un sélecteur de mois, ce qui permettait à nos utilisateurs de définir une plage de dates pour un rapport d'analyse.

Le point de départ que nous avons choisi était l'existant Bibliothèque de composants de matériaux . Plutôt que de partir de zéro, cette bibliothèque est activement maintenue et s'aligne sur les spécifications des matériaux. Avec cette bibliothèque comme base, nous pourrions probablement réduire la quantité de logique que nous devrons écrire nous-mêmes.

Dans cet article, je vais expliquer comment nous avons abordé ce processus, certains facteurs uniques dans la création de l'application Sprout pour Android, quelques «pièges» qui se sont manifestés (et ont été corrigés) en cours de route, et que savoir si vous êtes travaillant sur un projet similaire.

introduction

Les composants matériels Android 1.1.0 Version a introduit un nouveau composant d'interface utilisateur de sélecteur de dates. Un des ajouts bienvenus de ce nouveau MaterialDatePicker sur AppCompat CalendarView est la possibilité de sélectionner une plage de dates à l'aide d'une vue de calendrier ou d'un champ de saisie de texte.



L'ancien AppCompat CalendarView n'était pas très flexible. C'était un bon composant pour le cas d'utilisation limité qu'il était censé résoudre; autrement dit, sélectionner une date unique et des dates minimales et maximales facultatives pour spécifier une limite de plage de dates autorisée.

Le nouveau MaterialDatePicker a été construit avec plus de flexibilité pour permettre l'utilisation de fonctionnalités étendues de comportement. Il fonctionne à travers une série d'interfaces que l'on pourrait implémenter pour peaufiner et modifier le comportement du sélecteur.

Cette modification de comportement est effectuée au moment de l'exécution via un ensemble de fonctions de modèle de générateur sur le MaterialDatePicker.Builder classer.



Cela signifie que nous pouvons étendre le comportement de base de ce MaterialDatePicker grâce à des composants d'interface composables.

Remarque: Bien qu'il existe un certain nombre de composants différents, le MaterialDatePicker utilise, dans cet article, nous couvrirons uniquement le composant de sélection de date.


545 nombre d'anges amour

Sélecteur de plage de dates

L'équipe Android HASHTAGS était en train de créer notre section Rapports d'analyse.

Cette nouvelle section permettrait à nos utilisateurs de sélectionner un ensemble de filtres et un ensemble de plages de dates que le rapport couvrirait.

Le MaterialDatePicker est venu avec des composants prédéfinis que nous pourrions exploiter pour accomplir notre cas d'utilisation.

Pour notre cas le plus courant, permettant à un utilisateur de sélectionner une plage de dates, le pré-construit MaterialDatePicker suffirait:

Avec ce bloc de code, nous obtenons un sélecteur de dates qui permet aux utilisateurs de sélectionner une plage de dates.

Sélecteur de dates mensuel

L'un des rapports HASHTAGS qui propose une sélection de date plus unique est le rapport Twitter Trends.

Ce rapport diffère des autres en ce qu'au lieu d'autoriser tout type de plage de dates, il applique une sélection d'un seul mois, ce qui signifie qu'un utilisateur ne peut sélectionner que mars 2020 par rapport au 3 mars au 16 mars 2020.

Notre application Web gère cela en utilisant un champ de formulaire déroulant:

Le MaterialDatePicker ne dispose pas d'un moyen d'appliquer une telle restriction avec le sélecteur de plage de dates de matériau prédéfini décrit dans la section précédente. Heureusement, MaterialDatePicker a été construit avec des composants composables qui nous permettent d'étendre le comportement par défaut pour notre cas d'utilisation particulier.

Comportement de sélection de la date

Le MaterialDatePicker exploite a DateSelector comme interface utilisée pour la logique de sélection du sélecteur.

Depuis le Javadoc:

“Interface pour les utilisateurs de {@link MaterialCalendar} pour contrôler la façon dont le calendrier affiche et renvoie les sélections… »

Vous remarquerez que le MaterialDatePicker.Builder.dateRangePicker() renvoie une instance de générateur de RangeDateSelector, que nous avons utilisée dans l'exemple ci-dessus.

Cette classe est un sélecteur prédéfini qui implémente DateSelector.

Brainstorming sur un comportement de sélection de date mensuel

Pour notre cas d'utilisation, nous voulions un moyen de permettre à nos utilisateurs de sélectionner un mois entier comme plage de dates sélectionnée; par exemple. Mai 2020, avril 2020, etc.

Nous pensions que le pré-construit RangeDateSelector référencé ci-dessus nous a guidé la plupart du temps. Le composant permettait à un utilisateur de sélectionner une plage de dates et d'appliquer une bondir .

La seule chose qui manquait était un moyen d'imposer une sélection pour sélectionner automatiquement tout le mois. Le comportement par défaut de RangeDateSelector permet à l'utilisateur de sélectionner une date de début et une date de fin.

Nous voulions un comportement de sorte que lorsqu'un utilisateur sélectionne un jour dans le mois, le sélecteur sélectionne automatiquement le mois entier comme plage de dates.

La solution que nous avons choisie était d'étendre le RangeDateSelector puis remplacez le comportement de sélection du jour pour sélectionner automatiquement le mois entier à la place.

Heureusement, il existe une fonction que nous pouvons remplacer depuis l'interface DateSelector appelé: select(selection: Long).

Cette fonction sera appelée lorsqu'un utilisateur sélectionne un jour dans le sélecteur, le jour sélectionné étant passé en millisecondes UTC à partir de l'époque.

Implémentation d'un comportement de sélection de date mensuel

L'implémentation s'est avérée être la partie la plus simple, puisque nous avons une fonction claire que nous pouvons remplacer pour obtenir le comportement que nous voulons.

La logique de base sera la suivante:

  1. L'utilisateur sélectionne un jour.
  2. Le select() la fonction est appelée avec le jour sélectionné dans un Longue UTC millisecondes à partir de l'époque.
  3. Trouvez le premier et le dernier jour du mois à partir du jour donné qui nous est passé.
  4. Appeler super.select(1st of month) & super.select(last day of month)
  5. Le comportement parent de RangeDateSelector devrait fonctionner comme prévu et sélectionnez le mois comme plage de dates.

Mettre tous ensemble

Maintenant que nous avons notre Custom MonthRangeDateSelector, nous pouvons configurer notre MaterialDatePicker.

Pour aller plus loin dans l'exemple, nous pouvons traiter le résultat de la sélection comme ceci:

Le résultat ressemblera à ceci:

Gotchas

Un seul problème majeur a rendu difficile la recherche de cette solution.

Les principaux composants utilisés pour construire notre MonthRangeDateSelector était la classe RangeDateSelector et l'interface DateSelector. La version de la bibliothèque utilisée dans cet article (1.2.0-beta01) restreignait la visibilité de ces deux fichiers, pour décourager leur extension ou leur implémentation.

En conséquence, bien que nous ayons pu compiler avec succès notre nouveau MonthRangeDateSelector, le compilateur a montré un avertissement très effrayant pour nous décourager de le faire:

Une façon de masquer cet avertissement du compilateur consiste à ajouter un @Suppress('RestrictedApi') ainsi:

Cette expérience illustre comment, même si la bibliothèque de composants matériels a fourni de nouveaux composants intéressants à la communauté des développeurs Android, il s'agit toujours d'un travail en cours.

Une grande partie de cette bibliothèque est l'ouverture aux commentaires de la communauté Android! Après avoir découvert cette restriction de visibilité des composants, j'ai ouvert un problème sur le projet Github, et a même ouvert un PR pour y remédier tout de suite.

Cette boucle de rétroaction ouverte entre l'équipe des composants matériels et la communauté Android engendre une excellente collaboration et des résultats pour tous.

Conclusion

Le nouveau MaterialDatePicker a de très bonnes fonctionnalités prêtes à l'emploi qui couvriront probablement la plupart des cas d'utilisation de la sélection de date.

Cependant, la meilleure partie de celui-ci par rapport à quelque chose comme AppCompat CalendarView est qu'il est construit de manière composable. Par conséquent, il peut être facilement étendu et modifié pour des cas d'utilisation spécifiques, alors qu'il serait beaucoup plus difficile d'accomplir de telles choses dans le CalendarView.

Remerciement spécial

Je voudrais souligner quelques personnes qui ont contribué à l'examen par les pairs de cet article:

Partage Avec Tes Amis: