วิศวกรรมที่ Sprout: สร้างเครื่องมือเลือกเดือน Android

เผยแพร่แล้ว: 2020-06-26

หมายเหตุ: บทความนี้อิงตาม Material Components เวอร์ชัน 1.2.0-beta01 วันที่ 1 มิถุนายน 2020

ในช่วงสามปีครึ่งที่ฉันทำงานในทีม Android เล็กๆ ที่ Sprout Social สิ่งสำคัญอย่างหนึ่งที่กระตุ้นให้ฉันเข้ามาทำงานทุกวันคืออิสรภาพและความไว้วางใจจากบริษัทของเราในการแก้ไขปัญหาในแบบที่เราเห็นว่าดีที่สุด

อิสระในการวิจัยและสำรวจวิธีแก้ปัญหาต่างๆ มากมายสำหรับปัญหาที่เราเห็นว่าจำเป็น ในขณะที่พิจารณากรอบเวลาในการส่งมอบการอัปเดตผลิตภัณฑ์ ช่วยให้เราสามารถค้นหาโซลูชันที่ดีที่สุดสำหรับทั้งลูกค้าและซอฟต์แวร์ของเรา

ความท้าทายประการหนึ่งเกี่ยวข้องกับการสร้างองค์ประกอบ UI สำหรับคุณลักษณะการรายงานบนมือถือใหม่ของเรา องค์ประกอบใหม่นี้คือตัวเลือกหนึ่งเดือน ซึ่งทำให้ผู้ใช้ของเรากำหนดขอบเขตช่วงวันที่สำหรับรายงานการวิเคราะห์ได้

จุดเริ่มต้นที่เราเลือกคือไลบรารีส่วนประกอบวัสดุที่มีอยู่ แทนที่จะเริ่มต้นจากศูนย์ ไลบรารีนี้ได้รับการบำรุงรักษาอย่างจริงจังและสอดคล้องกับข้อกำหนดของวัสดุ ด้วยห้องสมุดนี้เป็นพื้นฐาน เราอาจลดจำนวนตรรกะที่เราต้องเขียนด้วยตัวเอง

ในบทความนี้ ฉันจะอธิบายวิธีที่เราดำเนินการในกระบวนการนี้ ปัจจัยเฉพาะบางอย่างในการสร้างแอป Sprout สำหรับ Android "gotchas" บางส่วนที่เกิดขึ้น (และแก้ไข) ตลอดเส้นทาง และสิ่งที่ต้องทราบหากคุณ ทำงานในโครงการที่คล้ายกัน

บทนำ

ส่วนประกอบวัสดุ Android 1.1.0 เปิดตัวแนะนำองค์ประกอบ UI ตัวเลือกวันที่ใหม่ ฟีเจอร์ใหม่ที่น่ายินดีอย่างหนึ่งของ MaterialDatePicker ใหม่บน AppCompat CalendarView คือความสามารถในการเลือกช่วงวันที่โดยใช้มุมมองปฏิทินหรือช่องป้อนข้อความ

AppCompat CalendarView แบบเก่าไม่ยืดหยุ่นมากนัก เป็นองค์ประกอบที่ดีสำหรับกรณีการใช้งานที่จำกัดซึ่งตั้งใจจะแก้ไข นั่นคือ การเลือกวันที่เดียวและวันที่ต่ำสุดและสูงสุดที่ไม่บังคับ เพื่อระบุขอบเขตวันที่ที่อนุญาต

MaterialDatePicker ใหม่สร้างขึ้นด้วยความยืดหยุ่นมากขึ้นเพื่อให้สามารถใช้ฟังก์ชันการทำงานที่เพิ่มขึ้นได้ มันทำงานผ่านชุดของอินเทอร์เฟซที่สามารถนำไปใช้เพื่อปรับแต่งและปรับเปลี่ยนพฤติกรรมของตัวเลือก

การปรับเปลี่ยนลักษณะการทำงานนี้ทำได้ในขณะใช้งานจริงผ่านชุดของฟังก์ชันรูปแบบตัวสร้างบนคลาส MaterialDatePicker.Builder

ซึ่งหมายความว่าเราสามารถขยายพฤติกรรมพื้นฐานของ MaterialDatePicker นี้ผ่านส่วนประกอบอินเทอร์เฟซที่เขียนได้

หมายเหตุ: แม้ว่า MaterialDatePicker จะมีส่วนประกอบหลายอย่าง แต่ในบทความนี้ เราจะครอบคลุมเฉพาะส่วนประกอบการเลือกวันที่เท่านั้น

ตัวเลือกช่วงวันที่

ทีมงาน Sprout Social Android กำลังสร้างส่วนรายงาน Analytics

ส่วนใหม่นี้จะอนุญาตให้ผู้ใช้ของเราเลือกชุดตัวกรองและชุดช่วงวันที่ที่รายงานจะครอบคลุม

MaterialDatePicker มาพร้อมกับส่วนประกอบที่สร้างไว้ล่วงหน้าบางส่วนที่เราสามารถใช้ประโยชน์ได้เพื่อให้กรณีการใช้งานของเราสำเร็จ

สำหรับกรณีทั่วไปของเรา การอนุญาตให้ผู้ใช้เลือกช่วงวันที่ MaterialDatePicker ที่สร้างไว้ล่วงหน้าก็เพียงพอแล้ว:

ด้วยบล็อกรหัสนี้ เราได้รับตัวเลือกวันที่ที่อนุญาตให้ผู้ใช้เลือกช่วงวันที่

ตัวเลือกวันที่รายเดือน

รายงาน Sprout Social ฉบับหนึ่งที่มีการเลือกวันที่ที่ไม่ซ้ำกันมากขึ้นคือรายงานแนวโน้มของ Twitter

รายงานนี้แตกต่างจากรายงานอื่นๆ ตรงที่แทนที่จะอนุญาตให้ใช้ช่วงวันที่ใดๆ แต่บังคับใช้การเลือกเดือนเดียว ซึ่งหมายความว่าผู้ใช้สามารถเลือกได้เฉพาะเดือนมีนาคม 2020 เทียบกับ 3 มีนาคม ถึง 16 มีนาคม 2020

เว็บแอปของเราจัดการสิ่งนี้โดยใช้ฟิลด์แบบฟอร์มดรอปดาวน์:

MaterialDatePicker ไม่มีวิธีบังคับใช้ข้อจำกัดดังกล่าวกับตัวเลือกช่วงวันที่ของวัสดุที่สร้างไว้ล่วงหน้าที่กล่าวถึงในส่วนก่อนหน้า โชคดีที่ MaterialDatePicker สร้างขึ้นด้วยชิ้นส่วนที่ประกอบได้ซึ่งช่วยให้เราสามารถขยายการทำงานเริ่มต้นสำหรับกรณีการใช้งานเฉพาะของเราได้

พฤติกรรมการเลือกวันที่

MaterialDatePicker ใช้ประโยชน์จาก DateSelector เป็นอินเทอร์เฟซที่ใช้สำหรับตรรกะการเลือกของตัวเลือก

จาก Javadoc:

“อินเทอร์เฟซสำหรับผู้ใช้ {@link MaterialCalendar<S>} เพื่อควบคุมวิธีที่ปฏิทินแสดงและส่งคืนการเลือก…”

คุณจะสังเกตเห็นว่า MaterialDatePicker.Builder.dateRangePicker() ส่งคืนอินสแตนซ์ตัวสร้างของ RangeDateSelector ซึ่งเราใช้ในตัวอย่างข้างต้น

คลาสนี้เป็นตัวเลือกที่สร้างไว้ล่วงหน้าซึ่งใช้งาน DateSelector

ระดมสมองพฤติกรรมการเลือกวันที่รายเดือน

สำหรับกรณีการใช้งานของเรา เราต้องการวิธีให้ผู้ใช้เลือกทั้งเดือนเป็นช่วงวันที่ที่เลือก เช่น พฤษภาคม 2020 เมษายน 2020 เป็นต้น

เราคิดว่า RangeDateSelector ที่สร้างไว้ล่วงหน้าที่อ้างอิงด้านบนช่วยให้เราไปถึงที่นั่นได้มากที่สุด คอมโพเนนต์อนุญาตให้ผู้ใช้เลือกช่วงวันที่และบังคับใช้ขอบเขต [ล่าง, บน]

สิ่งเดียวที่ขาดหายไปคือวิธีการบังคับใช้การเลือกเพื่อเลือกทั้งเดือนโดยอัตโนมัติ ลักษณะการทำงานเริ่มต้นของ RangeDateSelector ให้ผู้ใช้เลือกวันที่เริ่มต้นและวันที่สิ้นสุด

เราต้องการพฤติกรรมเพื่อที่ว่าเมื่อผู้ใช้เลือกวันในเดือนนั้น เครื่องมือเลือกจะเลือกทั้งเดือนโดยอัตโนมัติเป็นช่วงวันที่

โซลูชันที่เราตัดสินใจคือขยาย RangeDateSelector แล้วแทนที่พฤติกรรมการเลือกวันเพื่อเลือกทั้งเดือนโดยอัตโนมัติแทน

โชคดีที่มีฟังก์ชันที่เราสามารถแทนที่ได้จากอินเทอร์เฟซ DateSelector เรียกว่า: select(selection: Long)

ฟังก์ชันนี้จะถูกเรียกใช้เมื่อผู้ใช้เลือกวันในเครื่องมือเลือก โดยวันที่เลือกผ่านไปในหน่วยมิลลิวินาที UTC จากยุค

การใช้พฤติกรรมการเลือกวันที่รายเดือน

การใช้งานกลายเป็นส่วนที่ง่ายที่สุด เนื่องจากเรามีฟังก์ชันที่ชัดเจน เราจึงสามารถแทนที่เพื่อให้ได้พฤติกรรมที่เราต้องการ

ตรรกะพื้นฐานจะเป็นดังนี้:

  1. ผู้ใช้เลือกวัน
  2. ฟังก์ชัน select() ถูกเรียกใช้พร้อมกับวันที่เลือกในหน่วยมิลลิวินาทีแบบ ยาว UTC จากยุค
  3. หาวันแรกและวันสุดท้ายของเดือนจากวันที่กำหนดส่งมาถึงเรา
  4. โทรไปที่ super.select(1st of month) & super.select(last day of month)
  5. ลักษณะการทำงานหลักจาก RangeDateSelector ควรทำงานตามที่คาดไว้ และเลือกเดือนเป็นช่วงวันที่

วางมันทั้งหมดเข้าด้วยกัน

ตอนนี้เรามี Custom MonthRangeDateSelector แล้ว เราก็สามารถตั้งค่า MaterialDatePicker ของเราได้

เพื่อนำตัวอย่างเพิ่มเติม เราสามารถประมวลผลผลลัพธ์ของการเลือกดังนี้:

ผลลัพธ์จะมีลักษณะดังนี้:

Gotchas

มีปัญหาสำคัญเพียงปัญหาเดียวที่ทำให้เข้าถึงแนวทางแก้ไขปัญหานี้ได้ยาก

องค์ประกอบหลักที่ใช้ในการสร้าง MonthRangeDateSelector ของเราคือคลาส RangeDateSelector และอินเทอร์เฟซ DateSelector เวอร์ชันของไลบรารีที่ใช้ในบทความนี้ (1.2.0-beta01) จำกัดการเปิดเผยไฟล์ทั้งสองนี้ เพื่อไม่ให้ขยายหรือนำไปใช้

ด้วยเหตุนี้ แม้ว่าเราจะสามารถคอมไพล์ MonthRangeDateSelector ใหม่ของเราได้สำเร็จ แต่คอมไพเลอร์ก็แสดงคำเตือนที่น่ากลัวมากเพื่อไม่ให้เราทำเช่นนั้น:

วิธีหนึ่งในการซ่อนคำเตือนคอมไพเลอร์นี้คือการเพิ่ม @Suppress("RestrictedApi") เช่น:

ประสบการณ์นี้แสดงให้เห็นว่า แม้ว่าไลบรารีส่วนประกอบวัสดุได้มอบส่วนประกอบใหม่ที่ยอดเยี่ยมให้กับชุมชนนักพัฒนา Android แต่ก็ยังอยู่ในระหว่างดำเนินการ

ส่วนที่ดีของห้องสมุดนี้คือการเปิดกว้างเพื่อรับข้อเสนอแนะจากชุมชน Android! หลังจากค้นพบข้อจำกัดการมองเห็นส่วนประกอบนี้ ฉันได้เปิดปัญหาในโปรเจ็กต์ Github และเปิด PR เพื่อจัดการทันที

การวนรอบความคิดเห็นแบบเปิดนี้ระหว่างทีมส่วนประกอบวัสดุและชุมชน Android ทำให้เกิดความร่วมมือและผลลัพธ์ที่ยอดเยี่ยมสำหรับทุกคน

บทสรุป

MaterialDatePicker ใหม่มีฟังก์ชันการทำงานที่พร้อมใช้งานซึ่งน่าจะครอบคลุมกรณีการใช้งานส่วนใหญ่ในการเลือกวันที่

อย่างไรก็ตาม ส่วนที่ดีที่สุดของมันเหนือบางอย่างเช่น AppCompat CalendarView ก็คือมันถูกสร้างขึ้นในรูปแบบที่ประกอบได้ ดังนั้นจึงสามารถขยายและแก้ไขได้ง่ายสำหรับกรณีการใช้งานเฉพาะ ในขณะที่การทำสิ่งนี้ให้สำเร็จใน CalendarView จะยากกว่ามาก

ขอขอบคุณเป็นพิเศษ

ฉันต้องการเน้นบางคนที่ช่วยทบทวนบทความนี้:

  • นิค เร้าท์ (Github)
  • ไมค์ วูลฟ์สัน (Github)
  • ไรอัน ฟิลลิปส์ (LinkedIn)
  • ลูคัส โมลเลอร์ (Github)
  • มิต พาเทล (LinkedIn)