SwiftUI:更新由其他@State变量组成的@Binding变量的最佳方法
我在SwiftUI中遇到了我的第一个复杂控件。它是一个日期频率选择器,用户可以选择每周定期事件的星期几,或每月定期事件的月份。我有@State变量来跟踪我的段控制器中的周与月,以及用户选择的周或月的哪一天。当这些值改变时,我想更新@Binding频率。下面的代码正在运行,但我觉得更新body call中的频率有点脏SwiftUI:更新由其他@State变量组成的@Binding变量的最佳方法,swift,swiftui,Swift,Swiftui,我在SwiftUI中遇到了我的第一个复杂控件。它是一个日期频率选择器,用户可以选择每周定期事件的星期几,或每月定期事件的月份。我有@State变量来跟踪我的段控制器中的周与月,以及用户选择的周或月的哪一天。当这些值改变时,我想更新@Binding频率。下面的代码正在运行,但我觉得更新body call中的频率有点脏 enum Frequency { case weekly(on: Int) case monthly(on: Int) } struct FrequencyView
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"))
}
}
}
想知道是否有人找到了更好的方法吗?首先,将
工作日
和月日
的访问者添加到频率
:
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
}
然后在频率
中添加一个扩展名,以转换为段:
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 {
...
谢谢你!这让我更进一步了。当分段状态变量改变时,我如何改变频率?要将@Binding频率从每周更改为每月,我已经添加到我的答案中。我必须警告您,这对我来说在Xcode 11 beta 3中崩溃了。我在用macOS Mojave跑步。如果你在卡塔琳娜的话,也许会有用。无论如何,我提交了一份关于坠机的错误报告。为了澄清这一点,当我将选择器设置从“第0天”改为“第0天”,然后单击另一段时,我的测试项目崩溃。