Hinweis: Dieser Artikel basierte ab Version 1.2.0-beta01 von Material Components 1. Juni 2020.
Während meiner dreieinhalbjährigen Arbeit in einem kleinen Android-Team bei Sprout Social ist die Freiheit und das Vertrauen unseres Unternehmens, ein Problem so anzugehen, wie wir es für am besten halten, eines der wichtigsten Dinge, die mich jeden Tag zu meiner Arbeit motivieren.
Die Freiheit, viele verschiedene Lösungen für ein Problem, das wir für notwendig halten, zu recherchieren und zu erkunden und gleichzeitig einen Zeitrahmen für die Bereitstellung von Produktaktualisierungen zu haben, ermöglicht es uns, die beste Lösung sowohl für unsere Kunden als auch für unsere Software zu finden.
Eine dieser Herausforderungen bestand darin, eine UI-Komponente für unsere neue mobile Berichtsfunktion zu erstellen. Bei dieser neuen Komponente handelte es sich um eine Monatsauswahl, mit der unsere Benutzer einen Datumsbereich für einen Analysebericht festlegen konnten.
Als Ausgangspunkt wählten wir die bestehende Material Component Library. Anstatt bei Null anzufangen, wird diese Bibliothek aktiv gepflegt und an Materialspezifikationen angepasst. Mit dieser Bibliothek als Basis könnten wir wahrscheinlich die Menge an Logik reduzieren, die wir selbst schreiben müssten.
In diesem Artikel beschreibe ich, wie wir diesen Prozess angegangen sind, einige einzigartige Faktoren bei der Erstellung der Sprout-Android-App, einige „Fehler“, die im Laufe der Zeit aufgetreten sind (und behoben wurden) und was Sie wissen sollten, wenn Sie daran arbeiten ein Projekt. ähnlich.
Einführung
Mit Android Material Components Version 1.1.0 wurde eine neue UI-Komponente für die Datumsauswahl eingeführt. Eine der willkommenen Ergänzungen dieses neuen MaterialDatePicker gegenüber AppCompat CalendarView ist die Möglichkeit, einen Datumsbereich mithilfe einer Kalenderansicht oder eines Texteingabefelds auszuwählen.
Die alte AppCompat CalendarView war nicht sehr flexibel. Es war eine gute Komponente für den begrenzten Anwendungsfall, den sie lösen sollte; Das heißt, Sie wählen ein einzelnes Datum und optionale Mindest- und Höchstdaten aus, um eine zulässige Datumsbereichsbeschränkung anzugeben.
Der neue MaterialDatePicker wurde mit mehr Flexibilität erstellt, um die Verwendung erweiterter Verhaltensfunktionen zu ermöglichen. Es funktioniert über eine Reihe von Schnittstellen, die implementiert werden können, um das Verhalten des Selektors anzupassen und zu ändern.
Diese Verhaltensänderung erfolgt zur Laufzeit über eine Reihe von Builder-Musterfunktionen in der MaterialDatePicker.Builder-Klasse.
Das bedeutet, dass wir das Basisverhalten dieses MaterialDatePicker durch zusammensetzbare Schnittstellenkomponenten erweitern können.
Hinweis: Obwohl MaterialDatePicker eine Reihe unterschiedlicher Komponenten verwendet, behandeln wir in diesem Artikel nur die Datumsauswahlkomponente.
Datumsbereichsauswahl
Das Sprout Social Android-Team war gerade dabei, unseren Abschnitt für Analyseberichte zu erstellen.
Dieser neue Abschnitt würde es unseren Benutzern ermöglichen, eine Reihe von Filtern und eine Reihe von Datumsbereichen auszuwählen, die der Bericht abdecken würde.


MaterialDatePicker wurde mit einigen vorgefertigten Komponenten geliefert, die wir zur Umsetzung unseres Anwendungsfalls nutzen konnten.
Für unseren häufigsten Fall, bei dem ein Benutzer einen Datumsbereich auswählen kann, würde der vorgefertigte MaterialDatePicker ausreichen:
Mit diesem Codeblock erhalten wir eine Datumsauswahl, mit der Benutzer einen Datumsbereich auswählen können.

Monatliche Datumsauswahl
Einer der Sprout Social-Berichte mit einer einzigartigeren Datumsauswahl ist der Twitter Trendbericht.
Dieser Bericht unterscheidet sich von den anderen dadurch, dass er keinen beliebigen Datumsbereich zulässt, sondern eine einzelne Monatsauswahl anwendet, was bedeutet, dass ein Benutzer nur März 2020 und nicht den 3. bis 16. März 2020 auswählen kann.
Unsere Webanwendung erledigt dies über ein Dropdown-Formularfeld:

MaterialDatePicker bietet keine Möglichkeit, eine solche Einschränkung mit dem im vorherigen Abschnitt beschriebenen vorgefertigten Material Date Range Picker durchzusetzen. Glücklicherweise wurde MaterialDatePicker mit zusammensetzbaren Teilen erstellt, die es uns ermöglichen, das Standardverhalten für unseren speziellen Anwendungsfall zu erweitern.
Verhalten bei der Datumsauswahl
MaterialDatePicker nutzt einen DateSelector als Schnittstelle für die Auswahllogik des Selektors.
Aus dem Javadoc:
„Schnittstelle für {@link MaterialCalendar}-Benutzer, um zu steuern, wie der Kalender angezeigt wird und Auswahlen zurückgibt…“
Sie werden feststellen, dass MaterialDatePicker.Builder.dateRangePicker() eine Builder-Instanz von RangeDateSelector zurückgibt, die wir im obigen Beispiel verwendet haben.
Diese Klasse ist ein vorgefertigter Selektor, der DateSelector implementiert.
Überlegen Sie sich ein Verhalten bei der monatlichen Datumsauswahl
Für unseren Anwendungsfall wollten wir unseren Benutzern die Möglichkeit geben, einen ganzen Monat als ausgewählten Datumsbereich auszuwählen. zum Beispiel Mai 2020, April 2020 usw.
Wir glauben, dass der oben erwähnte vorgefertigte RangeDateSelector uns den größten Teil des Weges dorthin gebracht hat. Die Komponente ermöglichte es einem Benutzer, einen Datumsbereich auszuwählen und einen zu erzwingen [lower, upper] gebunden.
Das einzige, was fehlte, war eine Möglichkeit, eine Auswahl zu erzwingen, um automatisch den gesamten Monat auszuwählen. Das Standardverhalten von RangeDateSelector sieht vor, dass der Benutzer ein Startdatum und ein Enddatum auswählt.
Wir wollten ein Verhalten, bei dem der Selektor automatisch den gesamten Monat als Datumsbereich auswählt, wenn ein Benutzer einen Tag im Monat auswählt.

Die Lösung, für die wir uns entschieden haben, bestand darin, RangeDateSelector zu erweitern und dann das Tagesauswahlverhalten zu überschreiben, um automatisch den gesamten Monat auszuwählen.
Glücklicherweise gibt es eine Funktion namens select(selection: Long), die wir über die DateSelector-Schnittstelle überschreiben können.
Diese Funktion wird aufgerufen, wenn ein Benutzer einen Tag im Selektor auswählt, wobei der ausgewählte Tag seit der Epoche in UTC-Millisekunden vergangen ist.
Implementieren Sie ein monatliches Datumsauswahlverhalten
Die Implementierung erwies sich als der einfachste Teil, da wir eine klare Funktion haben, die wir überschreiben können, um das gewünschte Verhalten zu erhalten.
Die Grundlogik wird folgende sein:
- Der Benutzer wählt einen Tag aus.
- Die Funktion select() wird mit dem in a ausgewählten Tag aufgerufen Lang UTC-Millisekunden seit der Epoche.
- Finden Sie den ersten und letzten Tag des Monats ab dem angegebenen Tag, der uns passiert ist.
- Rufen Sie super.select (erster Tag des Monats) und super.select (letzter Tag des Monats) an.
- Das Hauptverhalten von RangeDateSelector sollte wie erwartet funktionieren und den Monat als Datumsbereich auswählen.
Alles zusammenfügen
Nachdem wir nun unseren benutzerdefinierten MonthRangeDateSelector haben, können wir unseren MaterialDatePicker konfigurieren.
Um das Beispiel weiterzuführen, können wir das Auswahlergebnis wie folgt verarbeiten:
Das Ergebnis wird so aussehen:

Fallstricke
Es gab nur ein großes Problem, das es schwierig machte, zu dieser Lösung zu gelangen.
Die Hauptkomponenten, die zum Erstellen unseres MonthRangeDateSelector verwendet wurden, waren die RangeDateSelector-Klasse und die DateSelector-Schnittstelle. Die in diesem Artikel verwendete Version der Bibliothek (1.2.0-beta01) schränkte die Sichtbarkeit dieser beiden Dateien ein, um ihre Erweiterung oder Implementierung zu verhindern.
Obwohl wir unseren neuen MonthRangeDateSelector erfolgreich kompilieren konnten, zeigte der Compiler eine sehr beängstigende Warnung an, um uns davon abzuhalten:

Eine Möglichkeit, diese Warnung vor dem Compiler zu verbergen, besteht darin, ein @Suppress(“RestrictedApi”) wie folgt hinzuzufügen:

Diese Erfahrung zeigt, dass die Material Components Library zwar einige großartige neue Komponenten für die Android-Entwickler-Community bereitgestellt hat, aber immer noch in Arbeit ist.
Ein großer Teil dieser Bibliothek ist die Offenheit für Feedback aus der Android-Community. Nachdem ich diese Einschränkung der Komponentensichtbarkeit entdeckt hatte, eröffnete ich ein Problem im Github-Projekt und eröffnete sogar eine PR, um das Problem sofort zu beheben.
Diese offene Feedbackschleife zwischen dem Material Components-Team und der Android-Community sorgt für eine großartige Zusammenarbeit und Ergebnisse für alle.
Abschluss
Der neue MaterialDatePicker verfügt über einige großartige sofort einsatzbereite Funktionen, die wahrscheinlich die meisten Anwendungsfälle für die Datumsauswahl abdecken.
Das Beste an etwas wie AppCompat CalendarView ist jedoch, dass es auf eine zusammensetzbare Weise aufgebaut ist. Es kann also leicht für bestimmte Anwendungsfälle erweitert und geändert werden, während es in CalendarView viel schwieriger wäre, solche Dinge zu erreichen.
Besonderen Dank
Ich möchte einige Personen hervorheben, die bei der Rezension dieses Artikels geholfen haben:
