背景
SwiftUIのDatePickerは何かと扱いが難しいと感じています。
例えば、DatePickerStyleのdefaultまたはcompactで表示されるselectionのラベルはカスタマイズができないようです。SwiftUIのDatePickerを扱ったことのある人であれば必ず通るのではないでしょうか?
本記事では、ラベルをカスタマイズする方法とその課題についても触れています。
表題の事象にハマった人の一助となれば幸いです。
1. graphycalでタップした時にサイズが変わってしまう問題の対処法
このような事象は許容できなくもないですが、できれば解決したいはずです。
以下のように.frame(width: 320)を追加することで回避できます。
widthを指定しなかったり、320以外のサイズにすると表題の事象または、サイズがおかしくなることを確認しています。
DatePicker(selection: $exhibitDate, displayedComponents: .date) {}
.datePickerStyle(.graphical)
.dynamicTypeSize(.large)
.frame(width: 320) // widthが320ではないとサイズが変わってしまう
こちらの記事を参考にしました。
https://stackoverflow.com/questions/73475000/datepicker-with-graphical-style-breaks-layout-constraints-on-ios-16-0
2.ラベルをカスタマイズする方法とその課題
DatePickerStyleのdefaultまたはcompactのスタイルでラベルをカスタマイズするのは簡単ではないようです。
モディファイアであれこれ試行錯誤するのを辞めて楽になりましょう。
解決策としては、DatePicker側のラベルが表示されないようにして、別でラベルのViewを用意すれば良いのです。
// 1. ラベルのViewを用意する
HStack {
Image(systemName: "calendar")
.font(.system(size: 17))
.foregroundStyle(.white)
Text(exhibitDate.formatted(.dateTime.year().month().day()))
.bold()
.font(.system(size: 17))
.foregroundStyle(.white)
}
// 2. 用意したViewに対してoverlayする
.overlay {
DatePicker(selection: $selectedDate, displayedComponents: .date) {}
.labelsHidden()
.opacity(0.011)
// 3. labelsHidden(),opacity(0.011)付与する。ラベルが見えなくなる
}
こちらの記事を参考にしました。
https://stackoverflow.com/questions/71254763/swiftui-compact-datepicker-with-custom-design
この実装の課題について
しかしながら、あくまでDatePickerのラベルは見えないだけで存在はしています。
そのため、見えないラベルがタップできなければカレンダーは表示されません。
ラベルが小さくてがユーザーがタップできない課題が発生します。
ラベルのサイズを大きくする方法は見つかりませんでした。
3. 多言語化(ローカライズ方法)について
.environment(.locale, Locale)を付与することで、DatePickerのラベルはローカライズされた表示となります。
シミュレータでも地域、言語を日本に設定することで、処理を確認することができます。
let locale = Locale(identifier: Locale.preferredLanguages[0])
// SwiftUI View内での処理
DatePicker(selection: $exhibitDate, displayedComponents: .date) {}
.environment(\.locale, locale)
言語設定についてはこちらの記事を参考にしました。
https://qiita.com/uhooi/items/a9c9d8b923005028ce4e
4.カレンダー(graphycal)をモーダルとして用意する
if showCalenderModal {
Color.black.opacity(0.3)
.edgesIgnoringSafeArea(.all)
.onTapGesture { showCalenderModal = false }
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundStyle(.white)
.frame(height: 320)
.padding(16)
DatePicker(selection: $exhibitDate, displayedComponents: .date) {}
.datePickerStyle(.graphical)
.dynamicTypeSize(.large)
.frame(width: 320) // widthが320ではないとサイズが変わってしまう
.padding(20)
.environment(\.locale, locale)
}
}