skip to Main Content

I have a UIViewRepresentable of a third-party library component FSCalendar. However, I need this to conform to type UIView… Is there a way to do this? Any help is appreciated 🙂

struct CalendarViewRepresentable: UIViewRepresentable {

    typealias UIViewType = FSCalendar
    var calendar = FSCalendar()

    @Binding var selectedDate: Date

    var calendarHeight: NSLayoutConstraint?


    func updateUIView(_ uiView: FSCalendar, context: Context) { }


    func makeUIView(context: Context) -> FSCalendar {

        calendar.delegate = context.coordinator
        calendar.dataSource = context.coordinator

        calendar.translatesAutoresizingMaskIntoConstraints = false

        calendar.setContentHuggingPriority(.required, for: .vertical)
        calendar.setContentHuggingPriority(.required, for: .horizontal)

        NSLayoutConstraint.activate([
            calendar.topAnchor.constraint(equalTo: context.coordinator.topAnchor)
        ])

        return calendar
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource {

        var parent: CalendarViewRepresentable

        init(_ parent: CalendarViewRepresentable) {
    
            self.parent = parent     
    
        }


        func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {

            parent.selectedDate = date
    
        }

        func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {

            parent.calendarHeight?.constant = bounds.height
            parent.calendar.layoutIfNeeded()
    
        }
 
    }

}

struct HomeView: View {

    @State private var selectedDate: Date = Date()

    var body: some View {
  
        VStack {
            CalendarViewRepresentable(selectedDate: self.$selectedDate)
        }

    }
}

2

Answers


  1. We usually wrap a UIKit view (UIView) to be UIViewRepresentable whenever we want to use this view in a SwiftUI context.
    SwiftUI works with a view element called View.

    On your case the UIKit view is FSCalendar, it’s originally a UIView and wrapping it to be a UIViewRepresentable is helping us using it in a SwiftUI context as a SwiftUI View – therefore there is no reason to convert or make UIViewRepresentable to a UIView.

    Login or Signup to reply.
  2. Your implementation of UIViewRepresentable with a Coordinator isn’t quite right, give this a try:

    import SwiftUI
    import FSCalendar
    
    struct CalendarViewRepresentable: UIViewRepresentable {
        
        @Binding var selectedDate: Date
        
        func makeCoordinator() -> Coordinator {
            Coordinator()
        }
        
        func makeUIView(context: Context) -> FSCalendar {
            return context.coordinator.calendar
        }
        
        func updateUIView(_ uiView: FSCalendar, context: Context) {
            uiView.select(selectedDate)
            context.coordinator.didSelectDate = { date in
                selectedDate = date
            }
        }
        
        class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource {
            
            lazy var calendar: FSCalendar = {
                let calendar = FSCalendar()
                calendar.delegate = self
                calendar.dataSource = self
                return calendar
            }()
            
            var didSelectDate: ((Date) -> ())?
            
            func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
                didSelectDate?(date)
            }
        }
    }
    
    struct FSCalendarTest: View {
        @State private var selectedDate = Date()
        
        var body: some View {
            NavigationStack {
                CalendarViewRepresentable(selectedDate: self.$selectedDate)
                    .navigationTitle("(selectedDate, format: .dateTime)")
                    .toolbar {
                        Button("Now") {
                            selectedDate = Date()
                        }
                    }
            }
        }
    }
    

    Screenshot

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search