【问题标题】:Linking ObservableObject to DatePicker in SwiftUI在 SwiftUI 中将 ObservableObject 链接到 DatePicker
【发布时间】:2023-10-09 12:16:01
【问题描述】:

我是 Swift 及其所有框架的新手。我有一个 JSON 文件,其中包含一年中每一天的读数。我为读数创建了一个Decodable 结构和一个将读数存储在数组中的ObservableObject 类。我已将ObservableObject 设为@EnvironmentObject,因此可以在所有视图中访问它。我可以将读数链接到日期选择器,以便选择日期将带我进入详细视图吗?

import SwiftUI

struct CalendarView: View {
    // this is where ObserveableObject is required
    @EnvironmentObject var days: Days
    
    @State private var date = Date()
    
    let dateFormatter: DateFormatter = {
       let formatter = DateFormatter()
        // formatter.dateStyle = .long
        formatter.dateFormat = "LLLL d"
        return formatter
    }()
    
    var body: some View {
        VStack {
            Text("Select a date to read")
                .font(.largeTitle)
            
            DatePicker("Select a date", selection: $date, displayedComponents: .date)
                .datePickerStyle(GraphicalDatePickerStyle())
                .labelsHidden()
                .frame(maxHeight: 400)
            
            Text("\(date, formatter: dateFormatter)")
        }
        .navigationTitle("Datepicker")
    }
}

struct CalendarView_Previews: PreviewProvider {
    static var previews: some View {
        CalendarView()
    }
}

【问题讨论】:

    标签: swift swiftui datepicker combine


    【解决方案1】:
    //Replace this with your Decodable object
    class Day : ObservableObject{
        let id: UUID = UUID()
        var date: Date
        init( date: Date) {
            self.date = date
        }
    }
    class CalendarViewModel: ObservableObject, Identifiable {
        
        @Published var days: [Day] = []
        @Published var selectedDate: Date = Date()
        
        var filteredDay: Day?{
            days.filter({
                Calendar.current.isDate($0.date, equalTo: selectedDate, toGranularity: .day)
            }).first
        }
        
        init() {
            //Create sample Days you can remove this and populate your array with acual data
            for n in 1...30{
                days.append(Day(date: Date().addingTimeInterval(TimeInterval(60*60*24*n))))
                days.append(Day(date: Date().addingTimeInterval(TimeInterval(-60*60*24*n))))
            }
        }
    }
    struct CalendarView: View {
        @StateObject var vm: CalendarViewModel = CalendarViewModel()
        
        @State var isVisible: Bool = false
        let dateFormatter: DateFormatter = {
            let formatter = DateFormatter()
            // formatter.dateStyle = .long
            formatter.dateFormat = "LLLL d"
            return formatter
        }()
        
        var body: some View {
            NavigationView{
                ScrollView {
                    Text("Select a date to read")
                        .font(.largeTitle)
                    
                    DatePicker("Select a date", selection: $vm.selectedDate, displayedComponents: .date)
                        .datePickerStyle(GraphicalDatePickerStyle())
                        .labelsHidden()
                        .frame(maxHeight: 400)
                    
                    Text("\(vm.selectedDate, formatter: dateFormatter)")
                    
                    if vm.filteredDay != nil{
                        NavigationLink(
                            destination: DayView(day: vm.filteredDay!),
                            isActive: $isVisible,
                            label: {
                                Text("View Day")
                            })
                    }else{
                        Text("No results for selected day")
                    }
                    
                }
                .navigationTitle("Datepicker")
            }
        }
        
    }
    struct DayView:View {
        //Observe the actual Day here for changes
        @ObservedObject var day: Day
        let dateFormatter: DateFormatter = {
            let formatter = DateFormatter()
            // formatter.dateStyle = .long
            formatter.dateFormat = "LLLL d"
            return formatter
        }()
        var body: some View {
            VStack{
                Text(dateFormatter.string(from: day.date))
            }
        }
    }
    

    【讨论】: