Home > Software design >  How to make the date change simultaneously in all views?
How to make the date change simultaneously in all views?

Time:12-27

Date not change simultaneously in all views. I want to link two calendars. Standard and custom. But they don't connect. When I change the date in one, it doesn't change in the other. I made Published:

import Combine
import Foundation

class CustomCalendar: ObservableObject {
    @Published var currentDate = Date()
    var currentThreeWeek: [Date] = []

    init() {
        fetchCurrentThreeWeek()
    }

    func fetchCurrentThreeWeek() {

        let calendar = Calendar.current

        var todayDay = DateInterval(start: Date(), duration: 1814400).start
        let lastDay = DateInterval(start: Date(), duration: 1814400).end

        currentThreeWeek.append(todayDay)

        while todayDay < lastDay {
            todayDay = calendar.date(byAdding: .day, value: 1, to: todayDay)!
            currentThreeWeek.append(todayDay)
        }
    }

    func extractDate(date: Date, format: String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = format
        dateFormatter.locale = Locale(identifier: "rus")
        return dateFormatter.string(from: date)
    }

    func isToday(date: Date) -> Bool {
        let calendar = Calendar.current
        return calendar.isDate(currentDate, inSameDayAs: date)
    }
}

When I select a date it doesn't change in other views.

import SwiftUI

struct FilterView: View {

    @StateObject private var calendar = CustomCalendar()
    @Binding var filterViewIsPresented: Bool
    
    let todayDay = DateInterval(start: Date(), duration: 1814400).start
    let lastDay = DateInterval(start: Date(), duration: 1814400).end

    var body: some View {
        VStack {
            DatePicker("", selection: $calendar.currentDate, in: todayDay...lastDay, displayedComponents: .date)
                .labelsHidden()
                .environment(\.locale, Locale.init(identifier: "ru"))
            HorizontalCalendarView()
            HorizontalCalendarView()
        }
    }
}

struct FilterView_Previews: PreviewProvider {
    static var previews: some View {
        FilterView(filterViewIsPresented: .constant(false))
    }
}

Custom calendar. On tap Gesture I change currentDate


import SwiftUI

struct HorizontalCalendarView: View {

    @StateObject private var calendar = CustomCalendar()

    var body: some View {
        ScrollViewReader { value in
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    ForEach(calendar.currentThreeWeek, id: \.self) { day in
                        VStack(spacing: 0) {

                            Text(calendar.extractDate(date: day, format: "dd"))
                                .font(.title3)
                                .fontWeight(.bold)

                            Text(calendar.extractDate(date: day, format: "EEE"))

                            RoundedRectangle(cornerRadius: 10, style: .continuous)
                                .frame(width: calendar.isToday(date: day) ? 40 : 0, height: 5)
                                .opacity(calendar.isToday(date: day) ? 1 : 0)
                                .padding(4)
                        }
                        .frame(width: 45, height: 45)
                        .foregroundStyle(calendar.isToday(date: day) ? .primary : .secondary )
                        .foregroundColor(calendar.isToday(date: day) ? .white : .black)
                        .padding(8)
                        .background(
                            ZStack {
                                if calendar.isToday(date: day) {
                                    RoundedRectangle(cornerRadius: 10, style: .continuous)
                                }
                            }
                        )
                        .onTapGesture {
                            withAnimation(.easeIn(duration: 0.2)) {
                                calendar.currentDate = day
                                value.scrollTo(calendar.currentDate, anchor: .leading)
                            }
                        }
                    }
                    .padding(9)
                }
            }
            Text(calendar.currentDate.formatted())
        }
    }
}

struct HorizontalCalendarView_Previews: PreviewProvider {
    static var previews: some View {
        HorizontalCalendarView()
    }
}


How can I do this?

CodePudding user response:

You have two options:

  1. Pass calendar in HorizontalCalendarView constructor and use @ObservedObject property wrapper instead of @StateObject:

struct HorizontalCalendarView: View {

    @ObservedObject private var calendar: CustomCalendar

    init(_ calendar: CustomCalendar) {
        self.calendar = calendar
    }

...

and just pass it in FilterView

HorizontalCalendarView(calendar)
  1. Another option is to use @EnvironmentObject (it's preferred method for deeply nested views in your example option 1 is better):
struct HorizontalCalendarView: View {

    @EnvironmentObject private var calendar: CustomCalendar = CustomCalendar()

...

then you have to pass calendar with environmentObject modifier:

HorizontalCalendarView().environmentObject(calendar)

Note: in order to @EnvironmentObject works as expected it is not necessary to use environmentObject modifier on actual view, you can use this modifier in any of parent views. That makes it perfect for deep nested views

  • Related