SwiftUI中ObservableObject搭配DatePicker的实现优化咨询
实现方案
第一步:改造DateHandler直接遵守ObservableObject
不需要额外的包装类,只要在存储属性的didSet中手动发送视图更新通知即可,兼容你已有的自定义getter/setter逻辑:
import SwiftUI class DateHandler: ObservableObject { var date1 : Date { didSet{ objectWillChange.send() // 手动通知视图属性变更 print("StartDate: \(date1)") } } var date2 : Date { didSet{ objectWillChange.send() // 手动通知视图属性变更 print("EndDate: \(date2)") } } var startDate:Date { get{ return date1 } set(newValue){ let adjustedDate = toLocalTime(date: newValue) // 直接把日期校验逻辑内聚到这里,不用放到视图层 guard adjustedDate < endDate else { return } date1 = adjustedDate } } var endDate:Date { get{ return date2 } set(newValue){ let adjustedDate = addOneDay(date: toLocalTime(date: newValue)) guard adjustedDate > startDate else { return } date2 = adjustedDate } } init(){ self.date1 = Date() self.date2 = addOneDay(date: toLocalTime(date: Date())) // 初始化默认结束日期比开始晚一天 } //Customize time zone func toLocalTime(date : Date) -> Date { let calendar = Calendar.current let timezone = TimeZone.current let seconds = TimeInterval(timezone.secondsFromGMT(for: date)) let newDate = calendar.date(bySettingHour: 00, minute: 00, second: 00, of: date) let dateLocalTimezone = Date(timeInterval: seconds, since: newDate!) return dateLocalTimezone } func addOneDay(date : Date) -> Date { let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: date) return tomorrow! } }
第二步:简化视图代码,省略中转State变量
现在可以直接把DatePicker绑定到DateHandler的属性,不需要额外的辅助变量和onChange/onAppear逻辑:
struct ContentView: View { // iOS14+用@StateObject,低版本用@ObservedObject即可 @StateObject var dateHandler = DateHandler() var body: some View { VStack(spacing: 20) { DatePicker("Date1", selection: Binding( get: { dateHandler.startDate }, set: { dateHandler.startDate = $0 } ), displayedComponents: .date) DatePicker("Date2", selection: Binding( get: { dateHandler.endDate }, set: { dateHandler.endDate = $0 } ), displayedComponents: .date) } .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
方案说明
- 直接让DateHandler遵守ObservableObject,利用
objectWillChange.send()手动触发变更通知,解决了自定义getter/setter无法使用@Published的问题,完全省略了冗余的DateHandlerHelper包装类 - 直接通过
Binding构造器绑定DatePicker到DateHandler的属性,不再需要中转的辅助State变量 - 把开始日期不能晚于结束日期的校验逻辑内聚到DateHandler内部,逻辑更聚合,视图层更干净
内容的提问来源于stack exchange,提问作者Jorge Reich
相关产品推荐
相关产品推荐

