我想从DatePicker
获取并设置日期,但是我的日期没有更新。 SwiftUI对我来说是新手,我对使用哪种类型的属性包装感到困惑。请提供帮助,并建议何时何地使用@State
,@Binding
,@Published
我读了一些文章,但我仍然不清楚概念。
在这里,我使用了MVVM和SwiftUI,代码如下。
class MyViewModel:ObservableObject {
@Published var selectedDate : Date = Date()
@Published var selectedDateStr : String = Date().convertDateToString(date: Date())
}
struct DatePickerView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@ObservedObject var viewModel : MyViewModel
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .long
return formatter
}
@State private var selectedDate = Date()
var body: some View {
VStack {
//Title
HStack{
Text("SELECT A DATE")
.foregroundColor(.white)
.font(.system(size: 20))
}
.frame(width:UIScreen.main.bounds.width,height: 60)
.background(Color.red)
//Date Picker
DatePicker(selection: $selectedDate, in: Date()-15...Date(), displayedComponents: .date) {
Text("")
}.padding(30)
Text("Date is \(selectedDate, formatter: dateFormatter)")
Spacer()
//Bottom buttons
Text("DONE")
.fontWeight(.semibold)
.frame(width:UIScreen.main.bounds.width/2,height: 60)
.onTapGesture {
self.viewModel.selectedDate = self.selectedDate
self.presentationMode.wrappedValue.dismiss()
}
}
}
}
//calling:
DatePickerView(viewModel: self.viewModel)
答案 0 :(得分:3)
回答关于您在SwiftUI中使用的包装器属性的第二个问题,即@ State,@ Binding,@ Published。
在SwiftUI中最常用的@Things是:
• @State - Binding<Value>
• @Binding - Binding<Value>
• @ObservedObject - Binding<Value> (*)
• @EnvironmentObject - Binding<Value> (*)
• @Published - Publisher<Value, Never>
(*)从技术上讲,我们获得了包装类型Wrapper的中间值,一旦我们将keyPath指定为对象内部的实际值,就变成了绑定。 因此,如您所见,SwiftUI中负责视图状态的大多数属性包装都被``投影''为Binding,用于在视图之间传递状态。 与普通课程不同的唯一包装是@Published,但是: 1.在Combine框架中声明,而不是在SwiftUI中声明 2.它具有不同的目的:使价值可观察 3.绝不用于视图的变量声明,仅在ObservableObject内部使用 考虑一下SwiftUI中的一个非常常见的场景,我们在其中声明一个ObservableObject并将其与视图中的@ObservedObject属性一起使用:
class ViewModel: ObservableObject {
@Published var value: Int = 0
}
struct MyView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View { ... }
}
MyView可以引用$ viewModel.value和viewModel。$ value-两个表达式都是正确的。相当令人困惑,不是吗? 这两个表达式最终代表不同类型的值:分别为Binding和Publisher。 两者都有实际用途:
var body: some View {
OtherView(binding: $viewModel.value) // Binding
.onReceive(viewModel.$value) { value // Publisher
// do something that does not
// require the view update
}
}
希望对您有帮助。
答案 1 :(得分:2)
您可以使用以下方法计算current date - 15 days
:
let previousDate = Calendar.current.date(byAdding: .day, value: -15, to: Date())!
然后在DatePicker的范围内使用previousDate
:
DatePicker(selection: $selectedDate, in: previousDate...Date(), displayedComponents: .date) { ...
总结,您的代码如下所示:
struct DatePickerView: View {
@Environment(\.presentationMode) var presentationMode
@ObservedObject var viewModel: MyViewModel
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .long
return formatter
}
@State private var selectedDate = Date()
let previousDate = Calendar.current.date(byAdding: .day, value: -15, to: Date())!
var body: some View {
VStack {
//Title
HStack{
Text("SELECT A DATE")
.foregroundColor(.white)
.font(.system(size: 20))
}
.frame(width:UIScreen.main.bounds.width,height: 60)
.background(Color.red)
//Date Picker
DatePicker(selection: $selectedDate, in: previousDate...Date(), displayedComponents: .date) {
Text("")
}.padding(30)
Text("Date is \(selectedDate, formatter: dateFormatter)")
Spacer()
//Bottom buttons
Button(action: {
self.viewModel.selectedDate = self.selectedDate
self.presentationMode.wrappedValue.dismiss()
}) {
Text("DONE")
.fontWeight(.semibold)
}
}
}
}
在Xcode 11.5,Swift 5.2.4中进行了测试。