Ta Reda På Ditt Antal Ängel
Ingenjör vid Sprout: Bygg en Android-månadsväljare
Obs! Den här artikeln baserades på materialkomponentversionen 1.2.0-beta01 från och med 1 juni 2020 .
Under mina tre och ett halvt år som arbetar på ett litet Android-team på HASHTAGS är en av de viktigaste sakerna som motiverar mig att komma till jobbet varje dag friheten och förtroendet från vårt företag att ta itu med ett problem på vilket sätt vi anser bäst.
Friheten att undersöka och utforska många olika lösningar på ett problem som vi anser nödvändiga, samtidigt som vi tar hänsyn till en tidsram för leverans av produktuppdateringar, gör det möjligt för oss att hitta den bästa lösningen för både våra kunder och vår programvara.
En sådan utmaning innebar att bygga en UI-komponent för vår nya Mobile Reporting-funktion. Den här nya komponenten var en månadsväljare, vilket gjorde det möjligt för våra användare att omfatta ett datumintervall för en analysrapport.
Startplatsen vi valde var den befintliga Materialkomponentbibliotek . Istället för att börja från grunden underhålls detta bibliotek aktivt och anpassas till materialspecifikationerna. Med detta bibliotek som grund kan vi sannolikt minska mängden logik som vi skulle behöva skriva själva.
I den här artikeln kommer jag att täcka hur vi närmade oss denna process, några unika faktorer för att bygga för Android-appen Sprout, några 'gotchas' som kom upp (och fixades) längs vägen, och vad man ska veta om du är arbetar med ett liknande projekt.
Introduktion
Androids materialkomponenter 1.1.0 Släpp introducerade en ny Date Picker UI-komponent. Ett av de välkomna tilläggen till detta nya MaterialDatePicker över AppCompat CalendarView är möjligheten att välja ett datumintervall med antingen en kalendervy eller ett textinmatningsfält.
Den gamla AppCompat CalendarView var inte särskilt flexibel. Det var en bra komponent för det begränsade användningsfall som det var tänkt att lösa; det vill säga att välja ett enda datum och valfria minimi- och maxdatum för att ange ett tillåtet datumintervall.
Den nya MaterialDatePicker byggdes med mer flexibilitet för att möjliggöra användning av utökad funktionalitet av beteende. Det fungerar genom en serie gränssnitt som man kan implementera för att justera och ändra plockarens beteende.
Denna beteendemodifiering görs vid körning genom en uppsättning byggmönsterfunktioner på MaterialDatePicker.Builder klass.
Det betyder att vi kan utöka grundbeteendet för detta MaterialDatePicker genom komponerbara gränssnittskomponenter.
Obs! Även om det finns ett antal olika komponenter är MaterialDatePicker använder, i denna artikel kommer vi endast att täcka komponenten för datumval.
nummer 1116
Datumintervallväljare
HASHTAGS Android-teamet var i färd med att bygga vårt avsnitt för Analytics-rapporter.
Det här nya avsnittet gör det möjligt för våra användare att välja en uppsättning filter och en uppsättning datumintervall som rapporten skulle täcka.
MaterialDatePicker kom med några förbyggda komponenter som vi kunde utnyttja för att uppnå vårt användningsfall.
För vårt vanligaste fall, att tillåta en användare att välja ett datumintervall, den förbyggda MaterialDatePicker skulle räcka:
Med detta kodblock får vi en Datumväljare som låter användare välja ett datumintervall.
Månadsväljare för datum
En av HASHTAGS-rapporterna som har ett mer unikt datumval är Twitter Trends Report.
Den här rapporten skiljer sig från de andra genom att i stället för att tillåta någon form av datumintervall, verkställer den ett val av en månad, vilket innebär att en användare bara kan välja mars 2020 mot 3 mars till 16 mars 2020.
Vår webbapp hanterar detta genom att använda ett rullgardinsformulärfält:
MaterialDatePicker har inte ett sätt att genomdriva en sådan begränsning med den förbyggda Material Date Range Picker som diskuterades i föregående avsnitt. Lyckligtvis byggdes MaterialDatePicker med komponerbara delar som gör att vi kan utöka standardbeteendet för vårt specifika användningsfall.
Datumval beteende
MaterialDatePicker utnyttjar a DateSelector som gränssnitt som används för urvalslogiken för plockaren.
Från Javadoc:
“Gränssnitt för användare av {@link MaterialCalendar} för att kontrollera hur kalendern visar och returnerar val ... ”
Du kommer att märka att MaterialDatePicker.Builder.dateRangePicker() returnerar en byggnadsinstans av RangeDateSelector, som vi använde i exemplet ovan.
Denna klass är en förbyggd väljare som implementerar DateSelector.
Brainstorming av ett månatligt datumvalbeteende
För vårt användningsfall ville vi ha ett sätt att få våra användare att välja en hel månad som ett valt datumintervall. t.ex. Maj 2020, april 2020, etc.
Vi trodde att den förbyggda RangeDateSelector som nämns ovan fick oss det mesta av vägen dit. Komponenten tillät en användare att välja ett datumintervall och genomdriva ett bunden .
Det enda som saknades var ett sätt att genomföra ett urval för att automatiskt välja hela månaden. Standardbeteendet för RangeDateSelector har användaren att välja ett startdatum och ett slutdatum.
Vi ville ha ett beteende så att när en användare väljer en dag i månaden, väljer plockaren sedan automatiskt hela månaden som datumintervall.
Lösningen vi bestämde oss för var att förlänga RangeDateSelector och åsidosätt sedan dagvalet för att automatiskt välja hela månaden istället.
Lyckligtvis finns det en funktion som vi kan åsidosätta från gränssnittet DateSelector kallas: select(selection: Long).
Denna funktion kommer att anropas när en användare väljer en dag i plockaren, med den valda dagen passerad i UTC millisekunder från epoken.
Implementera ett beteende för val av datum per månad
Implementeringen visade sig vara den enklaste delen, eftersom vi har en tydlig funktion som vi kan åsidosätta för att få det beteende vi vill ha.
Grundlogiken kommer att vara den här:
- Användaren väljer en dag.
select()funktionen anropas med den valda dagen i a Lång UTC millisekunder från epoken.- Hitta den första och sista dagen i månaden från den givna dagen till oss.
- Ring ett samtal till
super.select(1st of month)&super.select(last day of month) - Föräldrarnas beteende från
RangeDateSelectorska fungera som förväntat och välja månad som datumintervall.
Få alltid att falla på plats
Nu när vi har vår anpassade MonthRangeDateSelector kan vi ställa in vår MaterialDatePicker.
För att ta exemplet vidare kan vi bearbeta resultatet av urvalet så:
Resultatet kommer att se ut så här:
Gotchas
Det var bara en viktig fråga som gjorde det svårt att nå fram till denna lösning.
De primära komponenterna som används för att bygga vår MonthRangeDateSelector var klassen RangeDateSelector och gränssnittet DateSelector. Den version av biblioteket som används i den här artikeln (1.2.0-beta01) begränsade synligheten för dessa två filer för att motverka att förlänga eller implementera dem.
Som ett resultat, även om vi lyckades kompilera vårt nya MonthRangeDateSelector, visade kompilatorn en mycket läskig varning för att avskräcka oss från att göra det:
Ett sätt att dölja denna kompileringsvarning är att lägga till en @Suppress('RestrictedApi') såhär:
Denna erfarenhet illustrerar hur, trots att materialkomponentbiblioteket har tillhandahållit några fantastiska nya komponenter till Android Developer Community, är det fortfarande ett pågående arbete.
En stor del av detta bibliotek är öppenheten för feedback från Android Community! Efter att ha upptäckt denna komponents synbarhetsbegränsning öppnade jag en problem på Github-projektet och öppnade till och med en PR för att ta itu med det direkt.
Den här öppna feedbackslingan mellan Material Components Team och Android Community ger bra samarbete och resultat för alla.
Slutsats
Den nya MaterialDatePicker har en del bra out of the box-funktionalitet som sannolikt kommer att täcka de flesta användningsfall för datumval.
Den bästa delen av det över något som AppCompat CalendarView är dock att det är byggt på ett komponerbart sätt. Därför kan den enkelt förlängas och modifieras för specifika användningsfall, medan det skulle vara mycket svårare att åstadkomma sådana saker i CalendarView.
Speciellt tack
Jag vill lyfta fram några personer som har hjälpt till att granska denna artikel:
- Nick Rout ( Github )
- Mike Wolfson ( Github )
- Ryan Phillips ( LinkedIn )
- Lucas Moellers ( Github )
- Med Patel ( LinkedIn )
Dela Med Dina Vänner: