Sproutでのエンジニアリング:Androidの月間ピッカーの構築
公開: 2020-06-26注:この記事は、2020年6月1日現在のMaterialComponentsバージョン1.2.0-beta01に基づいています。
Sprout Socialで小さなAndroidチームで3年半働いている中で、毎日仕事に取り掛かる動機の1つは、私たちが最善と考える方法で問題に取り組むという会社からの自由と信頼です。
製品のアップデートを提供するための時間枠を考慮しながら、必要と思われる問題のさまざまな解決策を調査および調査する自由により、お客様とソフトウェアの両方に最適な解決策を見つけることができます。
そのような課題の1つは、新しいモバイルレポート機能のUIコンポーネントを構築することでした。 この新しいコンポーネントは月のピッカーであり、ユーザーは分析レポートの日付範囲を指定できました。
私たちが選んだ出発点は、既存のマテリアルコンポーネントライブラリでした。 このライブラリは、最初から始めるのではなく、積極的に維持され、マテリアルの仕様に準拠しています。 このライブラリを基盤として使用すると、自分で作成する必要のあるロジックの量を減らすことができる可能性があります。
この記事では、このプロセスにどのように取り組んだか、Sprout Androidアプリを構築する際のいくつかの固有の要因、途中で発生した(そして修正された)いくつかの「落とし穴」、およびあなたが同様のプロジェクトに取り組んでいます。
序章
Android Material Components 1.1.0リリースでは、新しいDatePickerUIコンポーネントが導入されました。 AppCompat CalendarView
に対するこの新しいMaterialDatePicker
の歓迎すべき追加の1つは、カレンダービューまたはテキスト入力フィールドのいずれかを使用して日付の範囲を選択する機能です。
古いAppCompatCalendarViewはあまり柔軟ではありませんでした。 これは、解決することを目的とした限られたユースケースに適したコンポーネントでした。 つまり、単一の日付とオプションの最小および最大日付を選択して、許可される日付範囲の範囲を指定します。
新しいMaterialDatePickerは、動作の拡張機能を使用できるように、より柔軟に構築されました。 これは、ピッカーの動作を微調整および変更するために実装できる一連のインターフェースを介して機能します。
この動作の変更は、実行時にMaterialDatePicker.Builder
クラスの一連のビルダーパターン関数を介して行われます。
これは、構成可能なインターフェイスコンポーネントを介して、このMaterialDatePicker
の基本的な動作を拡張できることを意味します。
注: MaterialDatePicker
が使用するさまざまなコンポーネントがありますが、この記事では、日付選択コンポーネントについてのみ説明します。
日付範囲ピッカー
Sprout Social Androidチームは、アナリティクスレポートセクションを作成中です。
この新しいセクションでは、ユーザーがレポートでカバーする一連のフィルターと一連の日付範囲を選択できるようになります。
MaterialDatePicker
には、ユースケースを実現するために活用できるいくつかのビルド済みコンポーネントが付属しています。
最も一般的なケースでは、ユーザーが日付の範囲を選択できるようにするために、事前に作成されたMaterialDatePicker
で十分です。
このコードブロックを使用すると、ユーザーが日付範囲を選択できる日付ピッカーを取得できます。
毎月の日付ピッカー
よりユニークな日付選択を備えたSproutSocialレポートの1つは、Twitterトレンドレポートです。
このレポートは、他のレポートとは異なり、任意の種類の日付範囲を許可する代わりに、1か月の選択を強制します。つまり、ユーザーは2020年3月と2020年3月3日から3月16日までしか選択できません。
私たちのウェブアプリは、ドロップダウンフォームフィールドを使用してこれを処理します。
MaterialDatePicker
には、前のセクションで説明したビルド済みのMaterial DateRangePickerでこのような制限を適用する方法がありません。 幸い、MaterialDatePickerは、特定のユースケースのデフォルトの動作を拡張できる構成可能なパーツで構築されています。
日付選択動作
MaterialDatePicker
は、ピッカーの選択ロジックに使用されるインターフェイスとしてDateSelector
を利用します。
Javadocから:
「 {@link MaterialCalendar<S>}
のユーザーが、カレンダーの表示方法と選択範囲の返却方法を制御するためのインターフェース…」
MaterialDatePicker.Builder.dateRangePicker()
が、上記の例で使用したRangeDateSelector
のビルダーインスタンスを返すことに気付くでしょう。
このクラスは、 DateSelector
を実装するビルド済みのセレクターです。
毎月の日付選択行動のブレインストーミング
私たちのユースケースでは、ユーザーが選択した日付範囲として1か月全体を選択できるようにする方法が必要でした。 例:2020年5月、2020年4月など。
上で参照したビルド済みのRangeDateSelector
が、ほとんどの方法でそこに到達したと考えました。 このコンポーネントにより、ユーザーは日付範囲を選択し、 [下限、上限]の範囲を適用できました。
欠けていたのは、月全体を自動選択するための選択を強制する方法だけでした。 RangeDateSelector
のデフォルトの動作では、ユーザーは開始日と終了日を選択します。
ユーザーがその月の日を選択すると、ピッカーがその月全体を日付範囲として自動選択するような動作が必要でした。
私たちが決定した解決策は、 RangeDateSelector
を拡張してから、日の選択動作をオーバーライドして、代わりに月全体を自動選択することでした。
幸い、 DateSelector
インターフェイスからオーバーライドできる関数select(selection: Long)
があります。
この関数は、ユーザーがピッカーで日を選択したときに呼び出され、選択した日はエポックからUTCミリ秒で渡されます。
毎月の日付選択動作の実装
実装は最も単純な部分であることがわかりました。これは、必要な動作を取得するためにオーバーライドできる明確な関数があるためです。
基本的なロジックは次のとおりです。
- ユーザーが日を選択します。
-
select()
関数は、エポックから長いUTCミリ秒の選択された日で呼び出されます。 - 私たちに渡された特定の日から月の最初と最後の日を見つけます。
-
super.select(1st of month)
とsuper.select(last day of month)
)を呼び出します RangeDateSelector
の親の動作は期待どおりに機能し、日付範囲として月を選択する必要があります。
すべてを一緒に入れて
カスタムMonthRangeDateSelector
ができたので、 MaterialDatePicker
を設定できます。
例をさらに進めるために、次のように選択の結果を処理できます。
結果は次のようになります。
ガッチャ
この解決策にたどり着くのを困難にした大きな問題が1つだけありました。
MonthRangeDateSelector
の構築に使用された主要なコンポーネントは、クラスRangeDateSelector
とインターフェースDateSelector
た。 この記事で使用されているライブラリのバージョン(1.2.0-beta01)は、これら2つのファイルの表示を制限し、それらを拡張または実装することを思いとどまらせました。
その結果、新しいMonthRangeDateSelector
を正常にコンパイルできましたが、コンパイラーは非常に恐ろしい警告を表示して、コンパイルを思いとどまらせました。
このコンパイラ警告を非表示にする1つの方法は、次のように@Suppress("RestrictedApi")
を追加することです。
この経験は、マテリアルコンポーネントライブラリがAndroidデベロッパーコミュニティにいくつかの優れた新しいコンポーネントを提供したにもかかわらず、それがまだ進行中の作業であることを示しています。
このライブラリの大部分は、Androidコミュニティからのフィードバックに対するオープン性です。 このコンポーネントの可視性の制限を発見した後、私はGithubプロジェクトで問題を開き、すぐにそれに対処するためにPRを開きました。
マテリアルコンポーネントチームとAndroidコミュニティの間のこのオープンなフィードバックループは、すべての人に素晴らしいコラボレーションと結果をもたらします。
結論
新しいMaterialDatePicker
には、日付選択のほとんどのユースケースをカバーする可能性が高い、すぐに使用できる優れた機能がいくつかあります。
ただし、AppCompat CalendarViewのようなものよりも優れている点は、構成可能な方法で構築されていることです。 したがって、特定のユースケースに合わせて簡単に拡張および変更できますが、 CalendarView
でそのようなことを実現するのははるかに困難です。
特別な感謝
この記事の査読を手伝ってくれた人々に焦点を当てたいと思います。
- Nick Rout(Github)
- マイク・ウルフソン(Github)
- ライアン・フィリップス(LinkedIn)
- Lucas Moellers(Github)
- Mit Patel(LinkedIn)