从日期选择器中获取和设置日期,但仍然使用旧的默认值

时间:2020-06-12 12:12:51

标签: swiftui

我想从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)

2 个答案:

答案 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中进行了测试。