📆
DatePickerとToggleを使ってDate?型を扱う
概要
-
Date?
を引数とし、それをDatePickerとToggleを持つViewで扱いたい。 - つまりは下記のような動作をさせたい。
参考
-
How can I run an action when a state changes?
- 尚プロパティに対する
didSet
に処理を書いてもViewには反映されない。
- 尚プロパティに対する
- onChange(of:perform:)
実装
- DatePickerとToggle用として、View自身にprivateなプロパティをもたせる
-
onAppear
で初期値をそれらに設定する。 - onChange(of:perform:) を使い、各アクションに対してプロパティを更新させる。
struct DateCellView: View {
let title: String
@Binding var date: Date?
@State private var selectedDate = Date()
@State private var isValid = false
private let dateRange: ClosedRange<Date> = {
return (Date.twitterStartedAt ?? Date())
...
Date()
}()
var body: some View {
HStack {
Text(title)
Spacer()
DatePicker("",
selection: $selectedDate,
in: dateRange,
displayedComponents: [.date]
)
.onChange(of: selectedDate) { newValue in
if isValid {
date = selectedDate
}
}
Toggle(isOn: $isValid) {}
.labelsHidden()
.onChange(of: isValid) { isOn in
date = isOn ? selectedDate : nil
}
}
.onAppear {
if let date = date {
selectedDate = date
isValid = true
}
}
}
}
extension Date {
static var twitterStartedAt: Date? {
let calendar = Calendar.current
let startComponents = DateComponents(year: 2006, month: 7, day: 15) // Twitterのサービス開始日時
return calendar.date(from: startComponents)
}
}
- 呼び出し例
struct DebugDateCellView: View {
@State private var date: Date? = nil
var body: some View {
VStack {
HStack {
Text("Current Value: ")
if let date = date {
Text(date, style: .date)
} else {
Text("isEmpty")
}
}
DateCellView(title: "Title", date: $date)
.frame(width: 300)
Spacer()
}
.onAppear() {
// 初期値を設定する場合
// date = Date.twitterStartedAt
}
}
}
Discussion