可选的 SwiftUI DatePicker 与 nil to Date 和 Date to nil 切换

Posted

技术标签:

【中文标题】可选的 SwiftUI DatePicker 与 nil to Date 和 Date to nil 切换【英文标题】:Optional SwiftUI DatePicker with nil to Date and Date to nil toggle 【发布时间】:2021-09-02 14:46:26 【问题描述】:

我正在尝试构建一个可以处理可选日期的 DatePicker。

我使用this post 作为起点...但目前我的代码在nilDate() 之间切换几次后就崩溃了。

我怎样才能使这段代码安全?

import SwiftUI

extension Date 
    public var m3d2y4: String 
        let formatter = DateFormatter()
        formatter.dateFormat = "MMM dd, yyyy"
        return formatter.string(from: self)
    


struct OptionalDatePicker: View 
    @Binding var date: Date?
    var nilText = "Never"
    var nilDate = Date()
    
    var body: some View 
        if let _ = date 
            datePicker
         else 
            nilTextButton
        
    
    
    private var dateBinding: Binding<Date> 
        Binding(get:  date ?? nilDate , set:  date = $0 )
    
    
    private var dateString: String 
        dateBinding.wrappedValue.m3d2y4
    

    private var nilTextButton: some View 
        Button(action: toggleDate) 
            Text(nilText)
        
    
    
    private var datePicker: some View 
        ZStack 
            HStack 
                Text(dateString)
                    .foregroundColor(.blue)
                Button(action:  toggleDate() ) 
                    Image(systemName: "xmark.circle")
                
            
            DatePicker("", selection: dateBinding, displayedComponents: [.date])
                .opacity(0.02) // minimum opacity to still allow tapping
                .labelsHidden()
        
    
    
    private func toggleDate() 
        if let _ = date 
            date = nil
         else 
            date = nilDate
        
    



struct OptionalDatePicker_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    
    
    struct ContentView: View 
        @State var date: Date? = nil
        
        var body: some View 
            HStack 
                Text("Ends")
                Spacer()
                OptionalDatePicker(date: $date)
            
            .padding()
        
    

提前致谢!

【问题讨论】:

你在这里做了一些奇怪的事情 - .opacity(0.02) 是一个原因。 选择器位于文本标签的前面,这样我仍然可以在点击时调出日历。如果opacity 设置为0,它就不再是可点击的(不知道为什么?)...通过反复试验,我确定.opacity(0.02) 是仍然允许并捕获点击的最低值。如果DatePicker 有一个isPresented 参数,例如NavigationLink,我认为我不需要这样做。 【参考方案1】:

注意到您在问题中链接到的 SO 帖子,我将在这里重复我的答案...

通过阅读Jim Dovey 的this blog,我几乎了解了有关 SwiftUI 绑定(使用核心数据)的所有知识。剩下的就是一些研究和几个小时的错误。

因此,当我使用 Jim 的技术在 SwiftUI Binding 上创建 Extensions 时,我们最终会得到类似这样的结果,以取消对 nil 的选择...

public extension Binding where Value: Equatable 
    init(_ source: Binding<Value>, deselectTo value: Value) 
        self.init(get:  source.wrappedValue ,
                  set:  source.wrappedValue = $0 == source.wrappedValue ? value : $0 
        )
    

然后可以像这样在整个代码中使用...

Picker("", 
       selection: Binding($date, deselectTo: nil),
       displayedComponents: [.date]
) 

...其中日期是可选的,例如...

@State private var date: Date?

【讨论】:

以上是关于可选的 SwiftUI DatePicker 与 nil to Date 和 Date to nil 切换的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 中的可选绑定

如何处理 swiftui @State optional unwrap

如何创建一个带有可选辅助 View 参数的 SwiftUI 视图?

如何使用 SwiftUI 和 Combine 检测 Datepicker 的值变化?

SwiftUI DatePicker 并不总是更新 State<Date> 变量

如何从 SwiftUI 中的图形样式 DatePicker 中删除侧边距?