Engineering at Sprout: creazione di un selettore di mesi Android
Pubblicato: 2020-06-26Nota: questo articolo era basato su Material Components versione 1.2.0-beta01 a partire dal 1 giugno 2020 .
Nei miei tre anni e mezzo di lavoro in un piccolo team Android presso Sprout Social, una delle cose principali che mi motiva a lavorare ogni giorno è la libertà e la fiducia della nostra azienda per affrontare un problema nel modo che riteniamo migliore.
La libertà di ricercare ed esplorare molte soluzioni diverse a un problema che riteniamo necessario, tenendo conto del lasso di tempo necessario per fornire gli aggiornamenti dei prodotti, ci consente di trovare la soluzione migliore sia per i nostri clienti che per il nostro software.
Una di queste sfide ha comportato la creazione di un componente dell'interfaccia utente per la nostra nuova funzione di reportistica mobile. Questo nuovo componente è stato un selettore di mesi, che ha consentito ai nostri utenti di definire un intervallo di date per un rapporto di analisi.
Il punto di partenza che abbiamo scelto è stata la libreria dei componenti dei materiali esistente. Invece di iniziare da zero, questa libreria viene attivamente mantenuta e si allinea con le specifiche del materiale. Con questa libreria come base, potremmo probabilmente ridurre la quantità di logica che dovremmo scrivere noi stessi.
In questo articolo, tratterò come ci siamo avvicinati a questo processo, alcuni fattori unici nella creazione dell'app Sprout per Android, alcuni "problemi" che sono emersi (e sono stati risolti) lungo il percorso e cosa sapere se lo sei lavorando su un progetto simile.
introduzione
La versione 1.1.0 di Android Material Components ha introdotto un nuovo componente dell'interfaccia utente per la selezione della data. Una delle aggiunte di benvenuto di questo nuovo MaterialDatePicker
su AppCompat CalendarView
è la possibilità di selezionare un intervallo di date utilizzando una visualizzazione calendario o un campo di immissione testo.
Il vecchio AppCompat CalendarView non era molto flessibile. Era un buon componente per il caso d'uso limitato che doveva risolvere; ovvero, selezionando una singola data e date minime e massime facoltative per specificare un limite di intervallo di date consentito.
Il nuovo MaterialDatePicker è stato creato con maggiore flessibilità per consentire l'utilizzo di funzionalità ampliate del comportamento. Funziona attraverso una serie di interfacce che è possibile implementare per modificare e modificare il comportamento del selettore.
Questa modifica del comportamento viene eseguita in fase di esecuzione tramite un set di funzioni del modello del builder nella classe MaterialDatePicker.Builder
.
Ciò significa che siamo in grado di estendere il comportamento di base di questo MaterialDatePicker
tramite componenti di interfaccia componibili.
Nota: sebbene ci siano diversi componenti utilizzati da MaterialDatePicker
, in questo articolo tratteremo solo il componente di selezione della data.
Selettore intervallo di date
Il team di Sprout Social Android stava costruendo la nostra sezione dei rapporti di analisi.
Questa nuova sezione consentirebbe ai nostri utenti di selezionare una serie di filtri e una serie di intervalli di date che sarebbero coperti dal rapporto.
Il MaterialDatePicker
è stato fornito con alcuni componenti pre-costruiti che potremmo sfruttare per realizzare il nostro caso d'uso.
Per il nostro caso più comune, consentendo a un utente di selezionare un intervallo di date, sarebbe sufficiente il MaterialDatePicker
predefinito:
Con questo blocco di codice, otteniamo un Date Picker che consente agli utenti di selezionare un intervallo di date.
Selettore di data mensile
Uno dei report di Sprout Social con una selezione di date più unica è il Twitter Trends Report.
Questo rapporto differisce dagli altri in quanto invece di consentire qualsiasi tipo di intervallo di date, impone una selezione di un solo mese, il che significa che un utente può selezionare solo marzo 2020 rispetto al 3 marzo al 16 marzo 2020.
La nostra app Web gestisce questo utilizzando un campo modulo a discesa:
MaterialDatePicker
non ha un modo per imporre tale restrizione con il Selettore intervallo di date materiale predefinito discusso nella sezione precedente. Fortunatamente, MaterialDatePicker è stato creato con parti componibili che ci consentono di espandere il comportamento predefinito per il nostro caso d'uso particolare.
Comportamento di selezione della data
Il MaterialDatePicker
sfrutta un DateSelector
come interfaccia utilizzata per la logica di selezione del picker.
Dal Javadoc:
"Interfaccia per gli utenti di {@link MaterialCalendar<S>}
per controllare come il Calendario visualizza e restituisce le selezioni..."
Noterai che MaterialDatePicker.Builder.dateRangePicker()
restituisce un'istanza del builder di RangeDateSelector
, che abbiamo usato nell'esempio sopra.
Questa classe è un selettore predefinito che implementa DateSelector
.
Brainstorming su un comportamento di selezione della data mensile
Per il nostro caso d'uso, volevamo un modo per fare in modo che i nostri utenti selezionassero un intero mese come intervallo di date selezionato; es. maggio 2020, aprile 2020, ecc.
Abbiamo pensato che il RangeDateSelector
pre-costruito di cui sopra ci avesse portato la maggior parte della strada lì. Il componente consentiva a un utente di selezionare un intervallo di date e imporre un limite [inferiore, superiore] .
L'unica cosa che mancava era un modo per imporre una selezione per selezionare automaticamente l'intero mese. Il comportamento predefinito di RangeDateSelector
prevede che l'utente selezioni una data di inizio e una data di fine.
Volevamo un comportamento in modo che quando un utente seleziona un giorno del mese, il selettore selezionerà automaticamente l'intero mese come intervallo di date.
La soluzione che abbiamo deciso era estendere il RangeDateSelector
e quindi ignorare il comportamento di selezione del giorno per selezionare automaticamente l'intero mese.
Fortunatamente, esiste una funzione che possiamo sovrascrivere dall'interfaccia DateSelector
chiamata: select(selection: Long)
.
Questa funzione verrà richiamata quando un utente seleziona un giorno nel selettore, con il giorno selezionato trascorso in millisecondi UTC dall'epoca.
Implementazione di un comportamento di selezione della data mensile
L'implementazione si è rivelata la parte più semplice, poiché abbiamo una funzione chiara che possiamo ignorare per ottenere il comportamento che desideriamo.
La logica di base sarà questa:
- L'utente seleziona un giorno.
- La funzione
select()
viene invocata con il giorno selezionato in un UTC lungo millisecondi dall'epoca. - Trova il primo e l'ultimo giorno del mese dal giorno dato che ci è passato.
- Effettua una chiamata a
super.select(1st of month)
esuper.select(last day of month)
- Il comportamento padre di
RangeDateSelector
dovrebbe funzionare come previsto e selezionare il mese come intervallo di date.
Mettere tutto insieme
Ora che abbiamo il nostro Custom MonthRangeDateSelector
, possiamo impostare il nostro MaterialDatePicker
.
Per portare ulteriormente l'esempio, possiamo elaborare il risultato della selezione in questo modo:
Il risultato sarà simile a questo:
Trabocchetti
C'era solo un problema importante che rendeva difficile arrivare a questa soluzione.
I componenti principali utilizzati per creare il nostro MonthRangeDateSelector
erano la classe RangeDateSelector
e l'interfaccia DateSelector
. La versione della libreria utilizzata in questo articolo (1.2.0-beta01) ha limitato la visibilità di questi due file, per scoraggiarne l'estensione o l'implementazione.
Di conseguenza, sebbene siamo riusciti a compilare con successo il nostro nuovo MonthRangeDateSelector
, il compilatore ha mostrato un avviso molto spaventoso per scoraggiarci dal farlo:
Un modo per nascondere questo avviso del compilatore è aggiungere un @Suppress("RestrictedApi")
in questo modo:
Questa esperienza illustra come, anche se la Material Components Library ha fornito alcuni fantastici nuovi componenti alla community di sviluppatori Android, è ancora un work in progress.
Gran parte di questa libreria è l'apertura al feedback della community Android! Dopo aver scoperto questa limitazione di visibilità dei componenti, ho aperto un problema sul progetto Github e ho persino aperto un PR per affrontarlo immediatamente.
Questo ciclo di feedback aperto tra il Material Components Team e la community Android genera grande collaborazione e risultati per tutti.
Conclusione
Il nuovo MaterialDatePicker
ha alcune fantastiche funzionalità pronte all'uso che probabilmente copriranno la maggior parte dei casi d'uso della selezione della data.
Tuttavia, la parte migliore di qualcosa come AppCompat CalendarView è che è costruito in modo componibile. Pertanto, può essere facilmente esteso e modificato per casi d'uso specifici, mentre sarebbe molto più difficile eseguire tali operazioni in CalendarView
.
Ringraziamenti speciali
Vorrei evidenziare alcune persone che hanno aiutato la revisione tra pari di questo articolo:
- Nick Rout (Github)
- Mike Wolfson (Github)
- Ryan Phillips (LinkedIn)
- Lucas Moellers (Github)
- Mit Patel (LinkedIn)