Version SwiftPM compatible Platform License

KVKCalendar

KVKCalendar 是一个高度可定制的日历。该库由五个模块组成,用于显示各种类型的日历(事件列表)。您可以选择任何模块或全部使用。它的设计基于标准的 iOS 日历,但具有额外的功能。时间轴显示当日和当周的日程安排。

附加功能

需要帮助?

如果您在应用程序中如何使用 KVKCalendar 方面有问题,请使用 KVKCalendar 标签在 StackOverflow 上提问。

请仅使用 Issues 来报告 bug 或请求库中的新功能

要求

安装

KVKCalendar 可通过 CocoaPodsSwift Package Manager 获取。

CocoaPods

pod 'KVKCalendar'

将 Pods 添加到 Xcode 项目

Swift Package Manager (Xcode 12 或更高版本)

  1. 在 Xcode 中,导航到 FileSwift PackagesAdd Package Dependency...
  2. 选择一个项目
  3. 粘贴存储库 URL (https://github.com/kvyatkovskys/KVKCalendar) 并单击 Next
  4. 对于 Rules,选择 Version (Up to Next Major) 并单击 Next
  5. 单击 Finish

将软件包依赖项添加到您的 App

UIKit 的用法

导入 KVKCalendar。创建一个子类视图 CalendarView 并实现 CalendarDataSource 协议。创建一个 [Event] 类的数组并返回该数组。

import KVKCalendar

class ViewController: UIViewController {
    var events = [Event]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let calendar = CalendarView(frame: frame)
        calendar.dataSource = self
        view.addSubview(calendar)
        
        createEvents { (events) in
            self.events = events
            self.calendarView.reloadData()
        }
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        // to track changing frame when an user rotates device
        calendarView.reloadFrame(view.frame)
    }
}

extension ViewController {
    func createEvents(completion: ([Event]) -> Void) {
        let models = // Get events from storage / API
        
        let events = models.compactMap({ (item) in
            var event = Event(ID: item.id)
            event.start = item.startDate // start date event
            event.end = item.endDate // end date event
            event.color = item.color
            event.isAllDay = item.allDay
            event.isContainsFile = !item.files.isEmpty
            event.recurringType = // recurring event type - .everyDay, .everyWeek
        
            // Add text event (title, info, location, time)
            if item.allDay {
                event.text = "\(item.title)"
            } else {
                event.text = "\(startTime) - \(endTime)\n\(item.title)"
            }
            return event
        })
        completion(events)
    }
}

extension ViewController: CalendarDataSource {
    func eventsForCalendar(systemEvents: [EKEvent]) -> [Event] {
        // if you want to get events from iOS calendars
        // set calendar names to style.systemCalendars = ["Test"]
        let mappedEvents = systemEvents.compactMap { Event(event: $0) }
        return events + mappedEvents
    }
}

实现 CalendarDelegate 来处理用户操作并控制日历行为。

calendar.delegate = self

要为特定事件或日期使用自定义视图,您需要创建一个 EventViewGeneral 类的新视图并在函数中返回该视图。

class CustomViewEvent: EventViewGeneral {
    override init(style: Style, event: Event, frame: CGRect) {
        super.init(style: style, event: event, frame: frame)
    }
}

// an optional function from CalendarDataSource
func willDisplayEventView(_ event: Event, frame: CGRect, date: Date?) -> EventViewGeneral? {
    guard event.ID == id else { return nil }
    
    return customEventView
}

要使用自定义日期单元格,只需订阅来自 CalendarDataSource 的这个可选方法(适用于日/周/月/年视图)。

func dequeueCell<T>(parameter: CellParameter, type: CalendarType, view: T, indexPath: IndexPath) -> KVKCalendarCellProtocol? where T: UIScrollView { 
    switch type {
    case .year:
        let cell = (view as? UICollectionView)?.dequeueCell(indexPath: indexPath) { (cell: CustomYearCell) in
            // configure the cell
        }
        return cell
    case .day, .week, .month:    
        let cell = (view as? UICollectionView)?.dequeueCell(indexPath: indexPath) { (cell: CustomDayCell) in
            // configure the cell
        }
        return cell
    case .list:    
        let cell = (view as? UITableView)?.dequeueCell { (cell: CustomListCell) in
            // configure the cell
        }
        return cell
    }
}

SwiftUI 的用法

添加一个新的 SwiftUI 文件并导入 KVKCalendar。创建一个结构体 CalendarViewDisplayable 并声明协议 UIViewRepresentable 用于连接 UIKitSwiftUI

import SwiftUI
import KVKCalendar

struct CalendarViewDisplayable: UIViewRepresentable {

    @Binding var events: [Event]
    var selectDate = Date()
    var style = Style()
    
    private var calendar = KVKalendarView(frame: .zero)
        
    func makeUIView(context: UIViewRepresentableContext<CalendarViewDisplayable>) -> KVKCalendarView {
        calendar.dataSource = context.coordinator
        calendar.delegate = context.coordinator
        return calendar
    }
    
    func updateUIView(_ uiView: KVKCalendarView, context: UIViewRepresentableContext<CalendarViewDisplayable>) {
        context.coordinator.events = events
    }
    
    func makeCoordinator() -> CalendarDisplayView.Coordinator {
        Coordinator(self)
    }
    
    public init(events: Binding<[Event]>) {
        _events = events
        calendar = KVKCalendarView(frame: frame, date: selectDate, style: style)
    }
    
    // MARK: Calendar DataSource and Delegate
    class Coordinator: NSObject, CalendarDataSource, CalendarDelegate {
        private let view: CalendarViewDisplayable
        
        var events: [Event] = [] {
            didSet {
                view.events = events
                view.calendar.reloadData()
            }
        }
        
        init(_ view: CalendarViewDisplayable) {
            self.view = view
            super.init()
        }
        
        func eventsForCalendar(systemEvents: [EKEvent]) -> [Event] {
            events
        }
    }
}

创建一个新的 SwiftUI 文件并将 CalendarViewDisplayable 添加到 body

import SwiftUI

struct CalendarContentView: View {
    @State var events: [Event] = []

    var body: some View {
        NavigationStack {
            CalendarViewDisplayable(events: $events)
        }
    }
}

样式

要自定义日历,创建一个对象 Style 并添加到 initCalendarView

public struct Style {
    public var event = EventStyle()
    public var timeline = TimelineStyle()
    public var week = WeekStyle()
    public var allDay = AllDayStyle()
    public var headerScroll = HeaderScrollStyle()
    public var month = MonthStyle()
    public var year = YearStyle()
    public var list = ListViewStyle()
    public var locale = Locale.current
    public var calendar = Calendar.current
    public var timezone = TimeZone.current
    public var defaultType: CalendarType?
    public var timeHourSystem: TimeHourSystem = .twentyFourHour
    public var startWeekDay: StartDayType = .monday
    public var followInSystemTheme: Bool = false 
    public var systemCalendars: Set<String> = []
}

作者

Sergei Kviatkovskii

许可

KVKCalendar 是在 MIT 许可证 下提供的