0

Newbie SwiftUI Dev here. I want to create a scheduling app in SwiftUI and I would like to create a button in navigation bar which change calendar's scope. From .week to month and return.

    struct HomeVC: View {
    
    init() {
        navbarcolor.configureWithOpaqueBackground()
        navbarcolor.backgroundColor = .systemGreen
        navbarcolor.titleTextAttributes = [.foregroundColor: UIColor.white]
        navbarcolor.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        UINavigationBar.appearance().standardAppearance = navbarcolor
        UINavigationBar.appearance().scrollEdgeAppearance = navbarcolor
       }
    
    @State private var selectedDate = Date()
    
var body: some View {
    NavigationView{
        VStack{
            CalendarRepresentable(selectedDate: $selectedDate)
                .frame(height: 300)
                .padding(.top, 15)
            
                Spacer()
           
                    ListView()
                }
            .navigationBarTitle("Calendar")
                .toolbar {
                    Button(action: {
                        switchCalendarScope()
                    }) {
                        Text("Toggle")
                    }
            }
        }
    }
}

This is my calendar struct, and I would like to take from here the switchCalendarScope function, and use it into button's action, but doesn't work.

struct CalendarRepresentable: UIViewRepresentable{
    typealias UIViewType = FSCalendar
    @Binding var selectedDate: Date
    var calendar = FSCalendar()
    
    func switchCalendarScope(){
        if calendar.scope == FSCalendarScope.month {
            calendar.scope = FSCalendarScope.week

        } else {
           calendar.scope = FSCalendarScope.month
        }

    }
    
    func updateUIView(_ uiView: FSCalendar, context: Context) { }
    
    func makeUIView(context: Context) -> FSCalendar {
        calendar.delegate = context.coordinator
        calendar.dataSource = context.coordinator
        calendar.allowsMultipleSelection = true
        calendar.scrollDirection = .vertical
        calendar.scope = .week
        
        //:Customization
        calendar.appearance.headerTitleFont =  UIFont.systemFont(ofSize: 25, weight: UIFont.Weight.heavy)
        calendar.appearance.weekdayFont = .boldSystemFont(ofSize: 15)
        calendar.appearance.weekdayTextColor = .black
        calendar.appearance.selectionColor = .systemGreen
        calendar.appearance.todayColor = .systemGreen
        calendar.appearance.caseOptions = [.headerUsesUpperCase, .weekdayUsesUpperCase]
        calendar.appearance.headerTitleColor = .black
        
        return calendar
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource {
        var parent: CalendarRepresentable
        var formatter = DateFormatter()
        
        init(_ parent: CalendarRepresentable) {
            self.parent = parent
        }

        func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
            return 0
        }
        
        func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
            formatter.dateFormat = "dd-MM-YYYY"
            print("Did select == \(formatter.string(from: date))")
        }
        
        func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
            formatter.dateFormat = "dd-MM-YYYY"
            print("Did de-select == \(formatter.string(from: date))")
        }
    }
}

Can anybody help?

1 Answers1

0

You don't need to trigger the function in your UIViewRepresentable. You simply need to declare a variable in there that is the representation of the selected scope, and pass that in with your initializer. I am going to assume that your scope variable is of Type Scope for this:

struct CalendarRepresentable: UIViewRepresentable {
    typealias UIViewType = FSCalendar
    @Binding var selectedDate: Date
    var calendar = FSCalendar()
    var scope: Scope
        
    func updateUIView(_ uiView: FSCalendar, context: Context) { }
    
    func makeUIView(context: Context) -> FSCalendar {
        calendar.delegate = context.coordinator
        calendar.dataSource = context.coordinator
        calendar.allowsMultipleSelection = true
        calendar.scrollDirection = .vertical

        // Set scope here
        calendar.scope = scope
        
        //:Customization

        ...

        return calendar
    }
...
}

Then from the HomeVC view you would call it like this:

        CalendarRepresentable(selectedDate: $selectedDate, scope: scope)

The view will get recreated as needed. Also, one last thing, in SwiftUI there are no ViewControllers. Your HomeVC should just be named Home. It is the view, not a view controller, and they work differently and take a different mental model. This is why you were struggling in solving this. Even the UIViewRepresentable is a view in the end, and it just wraps a ViewController and instantiates the view. And they are all structs; you don't mutate a struct, you simply recreate it when you need to change it.

Yrb
  • 8,103
  • 2
  • 14
  • 44