Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kvyatkovskys/kvkcalendar

A most fully customization calendar for Apple platforms 📅
https://github.com/kvyatkovskys/kvkcalendar

calendar calendar-view carthage cocoapods customization-calendar datepicker ios ios-calendar ios-swift kvkcalendar swift swift-package-manager timeline timeline-library

Last synced: 7 days ago
JSON representation

A most fully customization calendar for Apple platforms 📅

Awesome Lists containing this project

README

        

[![Version](https://img.shields.io/cocoapods/v/KVKCalendar.svg?style=flat)](https://cocoapods.org/pods/KVKCalendar)
[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-orange.svg)](https://swiftpackageindex.com/kvyatkovskys/KVKCalendar)
[![Platform](https://img.shields.io/cocoapods/p/KVKCalendar.svg?style=flat)](https://cocoapods.org/pods/KVKCalendar)
[![License](https://img.shields.io/cocoapods/l/KVKCalendar.svg?style=flat)](https://cocoapods.org/pods/KVKCalendar)

# KVKCalendar

**KVKCalendar** is a most fully customization calendar. Library consists of five modules for displaying various types of calendar (*day*, *week*, *month*, *year*, *list of events*). You can choose any module or use all. It is designed based on a standard iOS calendar, but with additional features. Timeline displays the schedule for the day and the week.

**Additional features:**
- [x] Switch between time zones
- [x] Dark mode
- [ ] Skeleton loading (month/list)
- [x] Custom event view
- [x] Custom date cell
- [x] Custom header view and collection view
- [x] Custom calendar localization
- [x] Event list mode for weekly viewing
- [x] Ability to set a divider line (day/week)
- [x] [Supporting Multiple Windows on iPad](https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multitasking/)
- [x] UIMenu supports in event view (iOS and Mac Catalyst 14.0+)
- [x] [Ability to configure the frame for viewing events](https://github.com/kvyatkovskys/KVKCalendar/pull/198)

## Need Help?

If you have a **question** about how to use KVKCalendar in your application, ask it on StackOverflow using the [KVKCalendar](https://stackoverflow.com/questions/tagged/kvkcalendar) tag.

Please, use [Issues](https://github.com/kvyatkovskys/KVKCalendar/issues) only for reporting **bugs** or requesting a new **features** in the library.

## Requirements

- iOS 13.0+, iPadOS 13.0+, MacOS 11.0+ (supports Mac Catalyst)
- Swift 5.0+

## Installation

**KVKCalendar** is available through [CocoaPods](https://cocoapods.org) or [Swift Package Manager](https://swift.org/package-manager/).

### CocoaPods
~~~bash
pod 'KVKCalendar'
~~~

[Adding Pods to an Xcode project](https://guides.cocoapods.org/using/using-cocoapods.html)

### Swift Package Manager (Xcode 12 or higher)

1. In Xcode navigate to **File** → **Swift Packages** → **Add Package Dependency...**
2. Select a project
3. Paste the repository URL (`https://github.com/kvyatkovskys/KVKCalendar`) and click **Next**.
4. For **Rules**, select **Version (Up to Next Major)** and click **Next**.
5. Click **Finish**.

[Adding Package Dependencies to Your App](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app)

## Usage for UIKit

Import `KVKCalendar`.
Create a subclass view `CalendarView` and implement `CalendarDataSource` protocol. Create an array of class `[Event]` and return the array.

```swift
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
}
}
```

Implement `CalendarDelegate` to handle user action and control calendar behaviour.

```swift
calendar.delegate = self
```

To use a custom view for specific event or date you need to create a new view of class `EventViewGeneral` and return the view in function.

```swift
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
}
```

To use a custom date cell, just subscribe on this optional method from `CalendarDataSource` (works for Day/Week/Month/Year views).
```swift
func dequeueCell(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
}
}
```

## Usage for SwiftUI

Add a new `SwiftUI` file and import `KVKCalendar`.
Create a struct `CalendarViewDisplayable` and declare the protocol `UIViewRepresentable` for connection `UIKit` with `SwiftUI`.

```swift
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) -> KVKCalendarView {
calendar.dataSource = context.coordinator
calendar.delegate = context.coordinator
return calendar
}

func updateUIView(_ uiView: KVKCalendarView, context: UIViewRepresentableContext) {
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
}
}
}
```

Create a new `SwiftUI` file and add `CalendarViewDisplayable` to `body`.

```swift
import SwiftUI

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

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

## Styles

To customize calendar create an object `Style` and add to `init` class `CalendarView`.

```swift
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 = []
}
```

## Author

[Sergei Kviatkovskii](https://github.com/kvyatkovskys)

## License

KVKCalendar is available under the [MIT license](https://github.com/kvyatkovskys/KVKCalendar/blob/master/LICENSE.md)