【问题标题】:In SwiftUI how can I use @State and @Binding to deal with different types?在 SwiftUI 中如何使用 @State 和 @Binding 来处理不同的类型?
【发布时间】:2020-10-25 05:08:44
【问题描述】:

由于标题可能不太清楚,下面是一个示例: 我有一个只是 DatePicker 的视图,名称是“MIMIRxDatePicker”

struct MIMIRxDatePicker: View {
@Binding var dobStr: String
@Binding var screenShouldGrayOut: Bool
    
var body: some View {
    VStack {
        Text("Select Date of Birth: \(dateFormatter.string(from: self.dobStr))")
        DatePicker(selection: self.dobStr , in: ...Date(), displayedComponents: .date) {
           Text("")
        }
        Button(action: {
                withAnimation {
                    self.screenShouldGrayOut.toggle()
                }
            }) {
                Text("Choose").foregroundColor(.white).padding()
                }.background(Color(Constants.ThemeColor)).cornerRadius(20)
        }.cornerRadius(10).frame(width: 270).padding(20).background(Color(.white))
    }
}

这是 MIMIRxDatePicker 的父视图:SignupContentView

struct SignupContentView: View {
    @State var email: String = ""
    @State var firstName: String = ""
    @State var lastName: String = ""
    @State var dobStr: String = ""
    @State var screenShouldGrayOut: Bool = false
    
    var body: some View {
        ZStack {
            Color(Constants.ThemeColor)
            ScrollView(.vertical) {
                Spacer().frame(height: 50)
                VStack (alignment: .center, spacing: 2) {
                    Spacer()
                    Group {
                        Group {
                            HStack {
                                Text("Email:").modifier(AuthTextLabelModifier())
                                Spacer()
                            }.padding(2)
                            
                            HStack {
                                Image(systemName: "envelope").foregroundColor(.white)
                                TextField("Email", text: $email).foregroundColor(.white)
                            }.modifier(AuthTextFieldContainerModifier())
                        }
                        
                        Group {
                            HStack {
                                Text("First Name:").modifier(AuthTextLabelModifier())
                                Spacer()
                            }.padding(2)
                            
                            HStack {
                                Image(systemName: "person").foregroundColor(.white)
                                TextField("First Name", text: $firstName).foregroundColor(.white)
                            }.modifier(AuthTextFieldContainerModifier())
                        }
                        
                        Group {
                            HStack {
                                Text("Last Name:").modifier(AuthTextLabelModifier())
                                Spacer()
                            }.padding(2)
                            HStack {
                                Image(systemName: "person").foregroundColor(.white)
                                TextField("Last Name", text: $lastName).foregroundColor(.white)
                            }.modifier(AuthTextFieldContainerModifier())
                            Spacer()
                            HStack { GenderSelector() }
                        }
                        
                        Group {
                            HStack {
                                Text("Date of Birth:").modifier(AuthTextLabelModifier())
                                Spacer()
                            }.padding(2)
                            HStack {
                                Image(systemName: "calendar").foregroundColor(.white)
                                TextField("", text: $dobStr).foregroundColor(.white).onTapGesture {
                                    
                                    withAnimation {
                                        self.screenShouldGrayOut.toggle()
                                    }
                                }
                            }.modifier(AuthTextFieldContainerModifier())
                        }
                    }
                }.padding()
            }.background(screenShouldGrayOut ? Color(.black) : Color(.clear)).navigationBarTitle("Sign Up", displayMode: .inline)
            if screenShouldGrayOut {
                MIMIRxDatePicker(dobStr: $dobStr, screenShouldGrayOut: $screenShouldGrayOut).animation(.spring())
            }
        }.edgesIgnoringSafeArea(.all)
    }
}

正如您所见,“SignupContentView”中的@State var dobStr 是一个字符串,它是需要的出生日期的TextField,但在MIMIRxDatePicker 中,DatePicker 的选择参数需要一个日期类型,而不是字符串,即使我声明了一个@Binding var dobStr: MIMIRxDatePicker 中的字符串。

我也试过了:

var dateFormatter: DateFormatter {
    let formatter = DateFormatter()
    formatter.dateStyle = .long
    return formatter
}

然后做:

DatePicker(selection: dateFormatter.date(from: self.dobStr)  , in: ...Date()....

但是没有用。

我知道假设如果 DatePicker 是 TextField,那么一切都会正常运行,因为 TextField 也只接受 String,但事实并非如此,我需要 DatePicker。

那么在 SwiftUI 中如何使用 @State 和 @Binding 来处理不同的类型呢?

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    您需要首先确定所涉及的类型。

    您将Binding<String> 传递给选择:它需要Binding<Date>

    @Binding var dobStr: String 仍然是Binding<String>

    dateFormatter.date(from: self.dobStr) 是日期,而不是 Binding<Date>

    您需要创建一个自定义 Binding<Date>,它的 getter/setter 与 Binding<String> 交互

    例如;

        Binding(
            get: { // return a Date from dobStr binding },
            set: { // set dobStr binding from a Date}
        )
    

    然后使用这个 Binding 作为参数来选择:

    【讨论】:

      【解决方案2】:

      您可以做的是使用Date操作String显示日期。

      这意味着您可以在 PickerText 视图中使用 Date 变量。

      struct MIMIRxDatePicker: View {
          @State var dob: Date
          ...
          
          let dateFormatter: DateFormatter = {
              let formatter = DateFormatter()
              formatter.dateStyle = .long
              return formatter
          }()
          
          var dobStr: String {
              dateFormatter.string(from: self.dob)
          }
      
          var body: some View {
              VStack {
                  // `String` for displaying...
                  Text("Select Date of Birth: \(self.dobStr)")
                  // and `Date` for date manipulation...
                  DatePicker(selection: self.$dob, in: ...Date(), displayedComponents: .date) {
                      Text("")
                  }
                  ...
              }
              ...
          }
      }
      

      然后在您的SignupContentView 中遵循相同的模式。通常尝试使用Date 对象进行日期操作,因为它们不太容易出错和格式错误的数据。

      【讨论】:

      • 只要要求是从 datepicker 到 Text 的单向关系,这将正常工作,就像在文本上使用 tapgesture 的情况一样。如果编码人员想要同时编辑日期为文本和日期选择器的能力,那么解决方案可能会因双向绑定而变得复杂。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      相关资源
      最近更新 更多