[Dalendar DevLog 7] カレンダーアプリの核心構造: ネストされたRecyclerViewで月間ビューを作る
月単位スクロールと日付グリッドを効率的に実装するために二重RecyclerView構造を採択した背景と詳細実装内容を紹介します。
![[Dalendar DevLog 7] カレンダーアプリの核心構造: ネストされたRecyclerViewで月間ビューを作る](/images/blog/dalendar_dev_7_recyclerview.png)
7編: カレンダーアプリの核心構造: ネストされたRecyclerViewで月間ビューを作る
1. 始めに: スクロール可能な月間カレンダーの目標設定
今回の文章では私が基本的な形態のカレンダーアプリをどのように実装したのか共有してみようと思います。核心要求事項は「一画面に一ヶ月ずつ表示」して、「左右スクロールを通じて移動」することでした。
2. 核心アーキテクチャ: 二重RecyclerView構造
私が実装したアプリの基本構造は2つのRecyclerViewをネストさせることです。参考コードの核心でもあるこの構造を通じて月単位の左右スクロールと月別日付グリッド表示を効率的に処理できました。
- メイン画面 (MainActivity): アプリが初めて実行されるとき現れる画面です。
- 月(Month)のためのRecyclerView (A): このRecyclerViewは各アイテムが一ヶ月全体を表します。左右にスクロールして月をめくることができます。
- 日(Day)のためのRecyclerView (B): このRecyclerViewはAの各アイテム内部にネストされた形態で存在します。6行7列のグリッド(Grid)レイアウトを持ち、計42個のアイテムがそれぞれ一日を表す方式です。
RecyclerViewは枠(viewholder)を再活用してシステム資源を効率的に使用します。レイアウトマネージャーを通じて再活用方式を自由に設定できるのが大きな長所です。
3. 実装詳細: 月(月)生成ロジック (RecyclerView A)
3.1. 「無限」スクロールのための初期位置設定
ユーザーが過去と未来、双方向にずっとスクロールできるように見せるために、私は月RecyclerView(A)の初期位置を非常に大きな値に設定しました。
// MainActivity.kt
scrollToPosition(Int.MAX_VALUE/2)
Int.MAX_VALUEの半分を開始位置に設定することで、ユーザーが左(過去)や右(未来)へスクロールするとき事実上果てしなく移動するかのような「無限スクロール」効果を実装できます。
3.2. スクロールによる月計算
実際の月(月)を計算するロジックは現在のpositionを基準にします。
calendar.add(Calendar.MONTH, position - center)
現在アイテムのpositionと中央位置(center)の差を計算して月を調整します。これのおかげで左右スクロールを通じて月が自然に変更されます。
4. 実装詳細: 日(日)生成ロジック (RecyclerView B)
各月に該当する6x7グリッド(計42個セル)の日付を生成するロジックは月RecyclerView(A)で計算された特定月を基準に行われます。
- リスト初期化: 42個の日付オブジェクトを入れるリストを生成します。
- 日付生成ループ: 該当月の1日が含まれた週の日曜日から始めて42個の日付を順次生成します。
- データ伝達: 日付がすべて埋まったdayListは最終的に日RecyclerView(B)を担当するアダプターに伝達されて画面に表示されます。
5. 仕上げ
参考コードを私のプロジェクトに合わせて適用しながらビューバインディング(view binding)を使用するようにコードを修正する小さな作業が必要でした。こうしてネストされたRecyclerViewを活用して月単位スクロールが可能なカレンダーの基本骨格を成功裏に完成させることができました。
![[Dalendar DevLog 1] プロジェクトの始まりと技術スタック選定](/images/blog/dalendar_dev_1_ideation.png)
![[Dalendar DevLog 2] 堅固なアプリの骨組み - アーキテクチャとデータ構造設計](/images/blog/dalendar_dev_2_architecture.png)
![[Dalendar DevLog 3] コア機能実装 1 (バックエンド & ロジック)](/images/blog/dalendar_dev_3_math_logic.png)