我遇到了SwiftUI中的第一个复杂控件。这是一个日期频率选择器,用户可以在其中选择每周定期事件的星期几,还是每月定期事件的月几。我有@State变量来跟踪我的细分控制器中的每周vs每月,以及用户选择在一周中的哪几日。当这些值更改时,我想更新@Binding频率。下面的代码可以正常工作,但是让我感觉不舒服,无法更新正文调用中的频率。
enum Frequency {
case weekly(on: Int)
case monthly(on: Int)
}
struct FrequencyView : View {
@Binding var frequency: Frequency
@State var segment: Int
@State var weekDay: Int
@State var monthDay: Int
var displayFrequency: Frequency {
if segment == 0 {
return .weekly(on: weekDay)
} else {
return .monthly(on: monthDay)
}
}
var body: some View {
frequency = displayFrequency
return NavigationView {
VStack {
Text(displayFrequency.long).fontWeight(.bold)
SegmentedControl(selection: $segment) {
Text("Weekly").tag(0)
Text("Monthly").tag(1)
}.padding()
if segment == 0 {
Text("Day of the week").foregroundColor(Acorns.stone)
ExpensesWeeklyPickerView(day: $weekDay).padding()
} else {
Text("Day of the month").foregroundColor(Acorns.stone)
ExpensesMonthlyPickerView(day: $monthDay).padding()
}
Spacer()
}.navigationBarTitle(Text("Frequency"))
}
}
}
好奇是否有人找到了更好的方法?
答案 0 :(得分:1)
首先,将weekDay
和monthDay
的访问器添加到Frequency
:
extension Frequency {
var weekDay: Int {
get {
if case .weekly(on: let day) = self { return day }
else { return 0 }
}
set { self = .weekly(on: newValue) }
}
var monthDay: Int {
get {
if case .monthly(on: let day) = self { return day }
else { return 0 }
}
set { self = .monthly(on: newValue) }
}
}
现在,您可以使用以下访问器为子视图创建绑定:
if segment == 0 {
Text("Day of the week").foregroundColor(Acorns.stone)
ExpensesWeeklyPickerView(day: $frequency.weekDay).padding()
} else {
Text("Day of the month").foregroundColor(Acorns.stone)
ExpensesMonthlyPickerView(day: $frequency.monthDay).padding()
}
要在单击段时更改频率,需要给SegmentedControl
绑定以更改频率。我将介绍另一个(专用)enum
用于该段:
fileprivate enum Segment: Int, Hashable {
case weekly
case monthly
}
然后在Frequency
上添加扩展名以与Segment
进行互译:
extension Frequency {
fileprivate var segment: ContentView.Segment {
get {
switch self {
case .weekly(on: _): return .weekly
case .monthly(on: _): return .monthly
}
}
set {
switch newValue {
case .weekly: self = .weekly(on: 0)
case .monthly: self = .monthly(on: 0)
}
}
}
}
最后,摆脱segment
属性,而改用frequency.segment
:
SegmentedControl(selection: $frequency.segment) {
Text("Weekly").tag(Segment.weekly)
Text("Monthly").tag(Segment.monthly)
}.padding()
if frequency.segment == .weekly {
...