【SwiftUI】DatePickerのようにスワイプで前後の月に移動できるカレンダーの作り方
https://waarumstudy.blogspot.com/2022/08/swiftuidatepicker.html
SwiftUIでiOS標準のDateePickerのように左右にスワイプして前後の月へ移動できるカレンダーを作れたのでメモしておきます。
完成図
スワイプで移動するロジック
- ZStackで連続した三ヶ月分のカレンダーを用意する
- 表示してるカレンダーの両隣の画面外に前後の月が来るようにオフセットを調整
- 3つのカレンダーそれぞれに月の数字と位置のインデックス-1,0,1を持たせる
- スワイプした時にインデックスのみを変更
- インデックスが-2もしくは2になった場合はインデックスを+/-3して-1から1の範囲に収め、月の数字を-/+3増減する
- インデックスが飛ぶ時の操作のみアニメーション無しにする
2. 表示してるカレンダーの両隣の画面外に前後の月が来るようにオフセットを調整
3. 3つのカレンダーそれぞれに位置のインデックス-1,0,1を持たせる
4. スワイプした時にインデックスのみを変更
5. インデックスが-2もしくは2になった場合はインデックスを+/-3して-1から1の範囲に収め、月の数字を-/+3増減する
6. インデックスが飛ぶ時の操作のみアニメーション無しにする
補足
カレンダー3つを横に並べるときにHStackではなくZStack+offsetを使うのは順番を変えられるようにするためです。
HStackにはZStackのZindexのような機能がないので、ZStackで3つのカレンダーを同じ初期位置に作り、変数を含んだoffsetで左右にずらしています。
offsetの引数を(画面幅 * 位置のインデックス)とすることで位置のインデックスを変えるだけで自動的にカレンダーが移動します。
ZStack {
SlideDaysView(month: $monthA).offset(x: offsetFor(indexA))
SlideDaysView(month: $monthB).offset(x: offsetFor(indexB))
SlideDaysView(month: $monthC).offset(x: offsetFor(indexC))
}.highPriorityGesture(drag)
func offsetFor(_ index: Int) -> CGFloat{
position.width + CGFloat(index) * Screen.width
}