在SwiftUI中将下一个/上一个按钮添加到FSCalendar

在SwiftUI中将下一个/上一个按钮添加到FSCalendar,swiftui,fscalendar,Swiftui,Fscalendar,我一直在玩,它帮助我建立了自己的定制日历 因为它是用UIKit编写的,所以我在将它集成到我的SwiftUI项目中时遇到了一些问题,例如在日历的两侧添加“下一个”和“上一个”按钮 这就是我到目前为止所做的: ContentView,我用一个HStack将按钮添加到日历的侧面 struct ContentView: View { let myCalendar = MyCalendar() var body: some View { HStack(spacing: 5) { B

我一直在玩,它帮助我建立了自己的定制日历

因为它是用UIKit编写的,所以我在将它集成到我的SwiftUI项目中时遇到了一些问题,例如在日历的两侧添加“下一个”和“上一个”按钮

这就是我到目前为止所做的:

ContentView,我用一个HStack将按钮添加到日历的侧面

struct ContentView: View {
let myCalendar = MyCalendar()
var body: some View {
    HStack(spacing: 5) {
        Button(action: {
            myCalendar.previousTapped()
        }) { Image("back-arrow") }
        MyCalendar()
        Button(action: {
            myCalendar.nextTapped()
        }) { Image("next-arrow") }
    }
}}
以及MyCalendar结构,为了集成FSCalendar库,它是一个UIViewRepresentable。 这也是我添加了两个功能(nextTapped和previousTapped)的地方,这两个功能应该会在点击按钮时更改显示的月份:

struct MyCalendar: UIViewRepresentable {

let calendar = FSCalendar(frame: CGRect(x: 0, y: 0, width: 320, height: 300))

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}
func makeUIView(context: Context) -> FSCalendar {
    
    calendar.delegate = context.coordinator
    calendar.dataSource = context.coordinator
    
    return calendar
}

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

func nextTapped() {
    let nextMonth = Calendar.current.date(byAdding: .month, value: 1, to: calendar.currentPage)
    calendar.setCurrentPage(nextMonth!, animated: true)
    print(calendar.currentPage)
}

func previousTapped() {
    let previousMonth = Calendar.current.date(byAdding: .month, value: -1, to: calendar.currentPage)
    calendar.setCurrentPage(previousMonth!, animated: true)
    print(calendar.currentPage)
}

class Coordinator: NSObject, FSCalendarDelegateAppearance, FSCalendarDataSource, FSCalendarDelegate {
    
    var parent: MyCalendar
    
    init(_ calendar: MyCalendar) {
        self.parent = calendar
    }
    
    func minimumDate(for calendar: FSCalendar) -> Date {
        return Date()
    }
    
    func maximumDate(for calendar: FSCalendar) -> Date {
        return Date().addingTimeInterval((60 * 60 * 24) * 365)
    }
}}
这就是它在模拟器中的样子:

正如您所看到的,只要点击下一个或上一个按钮,我就可以在终端上打印当前页面,但是当前页面在实际日历中没有改变。
如何解决此问题?

因为您正在使用
UIViewRepresentable
协议将UIView类与SwiftUI绑定在一起。在这里,您必须将-类型的对象与发布者一起使用,该发布者在对象更改之前发出消息。

您可以检查下面的代码以获得结果输出:(最欢迎编辑/改进)

输出:


接近它时,不要考虑在UIKit中如何完成(即忘记目标操作)。在ContentView中设置状态,如
currentDate
。这些按钮将改变这种状态。然后让日历在日期更改时做出响应-将date属性作为绑定传递到MyCalendar,协调器(不应该有对结构的引用,而是对UIView的引用)将在日期更改时通过更新MyCalendar结构的UIView进行响应。谢谢!这正是我需要的!
import SwiftUI
import UIKit
import FSCalendar
    
class CalendarData: ObservableObject{
        
   @Published var selectedDate : Date = Date()
   @Published var titleOfMonth : Date = Date()
   @Published var crntPage: Date = Date()
        
}
struct ContentView: View {
    
    @ObservedObject private var calendarData = CalendarData()
    
    var strDateSelected: String {
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .medium
        dateFormatter.timeStyle = .none
        dateFormatter.locale = Locale.current
        return dateFormatter.string(from: calendarData.selectedDate)
    }
    
    var strMonthTitle: String {
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMMM yyyy"
        dateFormatter.locale = Locale.current
        return dateFormatter.string(from: calendarData.titleOfMonth)
    }
    
    var body: some View {
        
        VStack {
            
            HStack(spacing: 100) {
                
                Button(action: {
                                    
                    self.calendarData.crntPage = Calendar.current.date(byAdding: .month, value: -1, to: self.calendarData.crntPage)!
                    
                }) { Image(systemName: "arrow.left") }
                    .frame(width: 35, height: 35, alignment: .leading)
                
                Text(strMonthTitle)
                .font(.headline)
                
                Button(action: {
                    
                    self.calendarData.crntPage = Calendar.current.date(byAdding: .month, value: 1, to: self.calendarData.crntPage)!
                    
                }) { Image(systemName: "arrow.right") }
                .frame(width: 35, height: 35, alignment: .trailing)
            }
            
            CustomCalendar(dateSelected: $calendarData.selectedDate, mnthNm: $calendarData.titleOfMonth, pageCurrent: $calendarData.crntPage)
                .padding()
                .background(
                    RoundedRectangle(cornerRadius: 25.0)
                        .foregroundColor(.white)
                        .shadow(color: Color.black.opacity(0.2), radius: 10.0, x: 0.0, y: 0.0)
                )
                .frame(height: 350)
                .padding(25)
            
            Text(strDateSelected)
            .font(.title)
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct CustomCalendar: UIViewRepresentable {
   
    typealias UIViewType = FSCalendar
    
    @Binding var dateSelected: Date
    @Binding var mnthNm: Date
    @Binding var pageCurrent: Date
    
    var calendar = FSCalendar()
    
    var today: Date{
        return Date()
    }
    
    func makeUIView(context: Context) -> FSCalendar {
        
        calendar.dataSource = context.coordinator
        calendar.delegate = context.coordinator
        calendar.appearance.headerMinimumDissolvedAlpha = 0
       
        return calendar
    }
    
    func updateUIView(_ uiView: FSCalendar, context: Context) {
        
        uiView.setCurrentPage(pageCurrent, animated: true) // --->> update calendar view when click on left or right button
    }
    
    func makeCoordinator() -> CustomCalendar.Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource {
        
        var parent: CustomCalendar
        
        init(_ parent: CustomCalendar) {
            
            self.parent = parent
        }

        func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
            
            parent.dateSelected = date
        }
        
        func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
            
            parent.pageCurrent = calendar.currentPage
            parent.mnthNm = calendar.currentPage
        }
    }
}