Engineering bei Sprout: Erstellen einer Android-Monatsauswahl

Veröffentlicht: 2020-06-26

Hinweis: Dieser Artikel basiert auf Material Components Version 1.2.0-beta01 vom 1. Juni 2020 .

In meinen dreieinhalb Jahren Arbeit in einem kleinen Android-Team bei Sprout Social ist eines der wichtigsten Dinge, die mich jeden Tag zur Arbeit motivieren, die Freiheit und das Vertrauen unseres Unternehmens, ein Problem so anzugehen, wie wir es für am besten halten.

Die Freiheit, viele verschiedene Lösungen für ein Problem zu erforschen und zu erforschen, die wir für notwendig halten, und gleichzeitig einen Zeitrahmen für die Bereitstellung von Produktaktualisierungen zu berücksichtigen, 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 Reporting-Funktion zu erstellen. Diese neue Komponente war eine Monatsauswahl, die es unseren Benutzern ermöglichte, einen Datumsbereich für einen Analysebericht festzulegen.

Als Ausgangspunkt wählten wir die bestehende Materialkomponentenbibliothek. Anstatt bei Null anzufangen, wird diese Bibliothek aktiv gepflegt und an den Materialspezifikationen ausgerichtet. Mit dieser Bibliothek als Grundlage könnten wir wahrscheinlich die Menge an Logik reduzieren, die wir selbst schreiben müssten.

In diesem Artikel werde ich behandeln, wie wir diesen Prozess angegangen sind, einige einzigartige Faktoren beim Erstellen der Sprout-Android-App, ein paar „Fallstricke“, die auf dem Weg aufgetreten sind (und behoben wurden), und was Sie wissen sollten, wenn Sie es sind an einem ähnlichen Projekt arbeiten.

Einführung

Mit der Version 1.1.0 von Android Material Components 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 entweder mit einer Kalenderansicht oder einem Texteingabefeld auszuwählen.

Die alte AppCompat CalendarView war nicht sehr flexibel. Es war eine gute Komponente für den begrenzten Anwendungsfall, den es lösen sollte; das heißt, Auswählen eines einzelnen Datums und optionaler minimaler und maximaler Daten, um eine zulässige Datumsbereichsgrenze 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 man implementieren könnte, um das Verhalten des Pickers zu optimieren und zu modifizieren.

Diese Verhaltensänderung erfolgt zur Laufzeit durch eine Reihe von Builder-Musterfunktionen in der MaterialDatePicker.Builder -Klasse.

Dies bedeutet, dass wir in der Lage sind, das Basisverhalten dieses MaterialDatePicker durch zusammensetzbare Schnittstellenkomponenten zu erweitern.

Hinweis: Obwohl es eine Reihe verschiedener Komponenten gibt, die der MaterialDatePicker verwendet, behandeln wir in diesem Artikel nur die Date Selection-Komponente.

Zeitraumauswahl

Das Sprout Social Android-Team war dabei, unseren Analytics-Berichtsbereich aufzubauen.

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.

Der MaterialDatePicker wurde mit einigen vorgefertigten Komponenten geliefert, die wir nutzen konnten, um unseren Anwendungsfall zu erfüllen.

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 eindeutigeren Datumsauswahl ist der Twitter-Trendbericht.

Dieser Bericht unterscheidet sich von den anderen dadurch, dass er, anstatt irgendeine Art von Datumsbereich zuzulassen, eine einzelne Monatsauswahl erzwingt, was bedeutet, dass ein Benutzer nur März 2020 und nicht den 3. März bis 16. März 2020 auswählen kann.

Unsere Web-App verarbeitet dies mithilfe eines Dropdown-Formularfelds:

Der MaterialDatePicker hat keine Möglichkeit, eine solche Einschränkung mit dem vorgefertigten Material Date Range Picker zu erzwingen, der im vorherigen Abschnitt besprochen wurde. 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

Der MaterialDatePicker nutzt einen DateSelector als Schnittstelle für die Auswahllogik des Pickers.

Aus dem Javadoc:

„Schnittstelle für Benutzer von {@link MaterialCalendar<S>} , um zu steuern, wie der Kalender die Auswahl anzeigt und zurückgibt …“

Sie werden feststellen, dass MaterialDatePicker.Builder.dateRangePicker() eine Builder-Instanz von RangeDateSelector , die wir im obigen Beispiel verwendet haben.

Diese Klasse ist ein vorgefertigter Selektor, der DateSelector implementiert.

Brainstorming eines monatlichen Datumsauswahlverhaltens

Für unseren Anwendungsfall wollten wir eine Möglichkeit, unsere Benutzer einen ganzen Monat als ausgewählten Datumsbereich auswählen zu lassen; B. Mai 2020, April 2020 usw.

Wir dachten, dass der vorgefertigte RangeDateSelector , auf den oben verwiesen wurde, uns den größten Teil des Weges dorthin gebracht hat. Die Komponente ermöglichte es einem Benutzer, einen Datumsbereich auszuwählen und eine [untere, obere] Grenze durchzusetzen .

Das einzige, was fehlte, war eine Möglichkeit, eine Auswahl zu erzwingen, um den gesamten Monat automatisch auszuwählen. Das Standardverhalten von RangeDateSelector vor, dass der Benutzer ein Startdatum und ein Enddatum auswählt.

Wir wollten ein Verhalten, bei dem der Picker 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, den RangeDateSelector zu erweitern und dann das Verhalten der Tagesauswahl zu überschreiben, um stattdessen den gesamten Monat automatisch auszuwählen.

Glücklicherweise gibt es eine Funktion, die wir von der Schnittstelle DateSelector namens: select(selection: Long) überschreiben können.

Diese Funktion wird aufgerufen, wenn ein Benutzer einen Tag in der Auswahl auswählt, wobei der ausgewählte Tag in UTC-Millisekunden seit der Epoche vergangen ist.

Implementieren eines monatlichen Datumsauswahlverhaltens

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:

  1. Der Benutzer wählt einen Tag aus.
  2. Die select() Funktion wird mit dem ausgewählten Tag in Long UTC Millisekunden von der Epoche aufgerufen.
  3. Finden Sie den ersten und letzten Tag des Monats ab dem angegebenen Tag, der uns übergeben wurde.
  4. Rufen super.select(1st of month) & super.select(last day of month)
  5. Das übergeordnete Verhalten 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 einrichten.

Um das Beispiel weiter zu führen, können wir das Ergebnis der Auswahl wie folgt verarbeiten:

Das Ergebnis wird wie folgt 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 Klasse RangeDateSelector und die Schnittstelle DateSelector . Die in diesem Artikel verwendete Version der Bibliothek (1.2.0-beta01) hat die Sichtbarkeit dieser beiden Dateien eingeschränkt, um davon abzuhalten, sie zu erweitern oder zu implementieren.

Obwohl wir unseren neuen MonthRangeDateSelector erfolgreich kompilieren konnten, zeigte der Compiler daher eine sehr beängstigende Warnung an, um uns davon abzuhalten:

Eine Möglichkeit, diese Compiler-Warnung auszublenden, besteht darin, @Suppress("RestrictedApi") wie folgt hinzuzufügen:

Diese Erfahrung zeigt, dass die Materialkomponentenbibliothek zwar einige großartige neue Komponenten für die Android-Entwicklergemeinschaft 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 Sichtbarkeit von Komponenten entdeckt hatte, eröffnete ich ein Problem im Github-Projekt und eröffnete sogar eine PR, um es sofort zu beheben.

Diese offene Feedback-Schleife zwischen dem Material Components-Team und der Android-Community bringt großartige Zusammenarbeit und Ergebnisse für alle hervor.

Fazit

Der neue MaterialDatePicker verfügt über einige großartige sofort einsatzbereite Funktionen, die wahrscheinlich die meisten Anwendungsfälle der Datumsauswahl abdecken.

Das Beste an etwas wie dem AppCompat CalendarView ist jedoch, dass es zusammensetzbar aufgebaut ist. Daher kann es für bestimmte Anwendungsfälle leicht erweitert und modifiziert werden, während es in der CalendarView viel schwieriger wäre, solche Dinge zu bewerkstelligen.

Besonderer Dank

Ich möchte einige Leute hervorheben, die beim Peer-Review dieses Artikels geholfen haben:

  • Nick Rout (Github)
  • Mike Wolfson (Github)
  • Ryan Phillips (LinkedIn)
  • Lucas Möllers (Github)
  • Mit Patel (LinkedIn)