簡體   English   中英

如何在 SwiftUI 中實現自定義日歷?

[英]How to Implement Custom Calendar in SwiftUI?

我需要使用自定義日歷而不是SwiftUI DatePicker 為此,我在創建的MyCalendar結構之后的Podfile中添加了pod 'KDCalendar', '~> 1.8.9' ,如下所示:

import SwiftUI
import KDCalendar

public struct MyCalendar: UIViewRepresentable {

    public func makeUIView(context: Context) -> CalendarView {
        return CalendarView()
    }

    public func updateUIView(_ calendar: CalendarView, context: Context) {
        let date: Date = Date()
        calendar.selectDate(date)
    }
}

當我打算在任何堆棧中使用它時,它只顯示周名稱和日歷的其他部分,從視圖中省略,並發生以下錯誤:

在此處輸入圖像描述

[Assert] negative or zero item sizes are not supported in the flow layout

非常希望您的合作能夠解決這個問題。

您也可以嘗試FSCalendar 它有點復雜,有很多可配置選項。 請找到最簡單的FSCalendar實現如下:

用法


import UIKit
import SwiftUI
import FSCalendar

MyCalendar().frame(minWidth: 200, minHeight: 320).padding(.leading, 5)

我的日歷


struct MyCalendar: UIViewControllerRepresentable {
    func makeUIViewController(context: UIViewControllerRepresentableContext<MyCalendar>) -> MyCalendarController {
        let calendar: MyCalendarController = .init()
        return calendar
    }

    func updateUIViewController(_ calendar: MyCalendarController, context: UIViewControllerRepresentableContext<MyCalendar>) {
        // MARK: - TODO
    }
}     

我的日歷控制器


class MyCalendarController: UIViewController, FSCalendarDelegateAppearance {
    let secondary: UIColor = .parse(0xE0B355)
    let primary  : UIColor = .parse(0x346C7C)
    let tersiary : UIColor = .parse(0xE7EEEF)
    
    fileprivate let formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()
    
    fileprivate weak var calendar: FSCalendar!
    
    override func loadView() {
        let width: CGFloat = UIScreen.main.bounds.width - 40
        let frame: CGRect  = .init(x: 0, y: 0, width: width, height: 300)
        let view:  UIView  = .init(frame: frame)
        self.view = view
        
        let calendar: FSCalendar = .init(frame: frame)
        calendar.allowsMultipleSelection = false
        calendar.dataSource = self
        calendar.delegate = self
        
        view.addSubview(calendar)
        self.calendar = calendar
        
        calendar.calendarHeaderView.backgroundColor = self.primary
        calendar.calendarWeekdayView.backgroundColor = self.primary
        calendar.appearance.headerTitleColor = self.tersiary
        calendar.appearance.weekdayTextColor = self.tersiary
        
        calendar.appearance.eventSelectionColor = self.tersiary
        calendar.appearance.eventDefaultColor = self.primary
        calendar.appearance.eventOffset = CGPoint(x: 0, y: -7)
        
        calendar.appearance.todaySelectionColor = self.primary
        calendar.appearance.selectionColor = self.secondary
        calendar.appearance.todayColor = self.primary
        
        calendar.appearance.titleWeekendColor = self.secondary
        calendar.appearance.titleDefaultColor = self.primary

        calendar.swipeToChooseGesture.isEnabled = true
        let scopeGesture = UIPanGestureRecognizer(target: calendar, action: #selector(calendar.handleScopeGesture(_:)));
        scopeGesture.delegate = self
        calendar.addGestureRecognizer(scopeGesture)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.calendar.scope = .month
        self.calendar.select(Date.init())
        self.calendar.accessibilityIdentifier = "calendar"
    }
}

擴展


extension MyCalendarController: FSCalendarDataSource {
    func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
        debugPrint("did select date \(self.formatter.string(from: date))")
        let selectedDates = calendar.selectedDates.map({self.formatter.string(from: $0)})
        debugPrint("selected dates is \(selectedDates)")
        if monthPosition == .next || monthPosition == .previous {
            calendar.setCurrentPage(date, animated: true)
        }
    }
}

extension MyCalendarController: FSCalendarDelegate {
    func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
        self.calendar.frame.size.height = bounds.height
        self.view.layoutIfNeeded()
    }
}

extension MyCalendarController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        debugPrint("UIGestureRecognizer")
        return true
    }
}

extension UIColor {
    static func parse(_ hex: UInt32, alpha: Double = 1.0) -> UIColor {
        let red   = CGFloat((hex & 0xFF0000) >> 16)/256.0
        let green = CGFloat((hex & 0xFF00) >> 8)/256.0
        let blue  = CGFloat(hex & 0xFF)/256.0
        return UIColor(red: red, green: green, blue: blue, alpha: CGFloat(alpha))
    }
}

要查看KDCalendar ,只需添加數據源和委托,如下所示。 這將解決KDCalendar渲染問題。


import SwiftUI
import KDCalendar

public struct MyCalendar: UIViewRepresentable {
    var date: Date = .init()

    public func makeUIView(context: Context) -> CalendarView {
        let calendar: CalendarView = .init()
        calendar.setDisplayDate(self.date, animated: false)
        calendar.selectDate(self.date)
        calendar.dataSource = self
        calendar.delegate = self
        return calendar;
    }

    public func updateUIView(_ calendar: CalendarView, context: Context) {
        calendar.selectDate(self.date)
    }
}

extension MyCalendar: CalendarViewDataSource {
    public func startDate() -> Date {
        return Date.init()
    }

    public func endDate() -> Date {
        var month:DateComponents = .init()
        month.month = 2
        return Calendar.current.date(byAdding: month, to: Date.init())!
    }

    public func headerString(_ date: Date) -> String? {
        return nil
    }
}


extension MyCalendar: CalendarViewDelegate {
    public func calendar(_ calendar: CalendarView, didDeselectDate date: Date) {}
    public func calendar(_ calendar: CalendarView, didScrollToMonth date: Date) {}
    public func calendar(_ calendar: CalendarView, didSelectDate date: Date, withEvents events: [CalendarEvent]) {}
    public func calendar(_ calendar: CalendarView, didLongPressDate date: Date, withEvents events: [CalendarEvent]?) {}

    public func calendar(_ calendar: CalendarView, canSelectDate date: Date) -> Bool {
        return true
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM