KVKCalendar 0.6.25

KVKCalendar 0.6.25

Sergei Kviatkovskii 维护。



 

CI Status Version Carthage SwiftPM compatible Platform License

KVKCalendar

KVKCalendar 是一个高度可定制的日历库。它包含五个模块,用于显示各种类型的日历(事件列表)。您可以选择任何模块或使用所有模块。它是基于标准 iOS 日历设计的,但增加了更多功能。时间轴显示了日和周的计划。

其他功能

  • 切换时区
  • 深色模式
  • 骨架加载(月/列表)
  • 自定义事件视图
  • 自定义日期单元格
  • 自定义标题视图和集合视图
  • 自定义日历本地化
  • 支持按周查看事件列表模式
  • 设置分隔线(日/周)
  • 支持在 iPad 上使用多个窗口
  • 事件视图中支持 UIMenu(iOS 和 Mac Catalyst 14.0+)
  • 配置查看事件框架的能力

需要帮助?

如果您在使用 KVKCalendar 的应用中遇到任何 问题,请使用 KVKCalendar 标签在 StackOverflow 上提问。

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

要求

  • iOS 13.0+、iPadOS 13.0+、MacOS 11.0+(支持Mac Catalyst)
  • Swift 5.0+

安装

KVKCalendar 可以通过 CocoaPodsCarthageSwift Package Manager 获取。

CocoaPods

pod 'KVKCalendar'

将Pods添加到Xcode项目中

Carthage

github "kvyatkovskys/KVKCalendar"

将框架添加到Xcode项目中

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

  1. 在Xcode中,导航至 文件Swift包添加包依赖...
  2. 选择一个项目
  3. 粘贴仓库URL(https://github.com/kvyatkovskys/KVKCalendar.git)并点击 下一步
  4. 对于 规则,选择 版本(更新至下一个主要版本) 并点击 下一步
  5. 点击 完成

将包依赖添加到您的应用

对于 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 的结构体并声明用于将 UIKitSwiftUI 连接的协议 UIViewRepresentable

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 对象并将其添加到 CalendarViewinit 类中。

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许可证