An Easy to Use Calendar for iOS (Swift 5.0)

Overview

Karmadust

Language License: MIT CocoaPods Awesome Carthage compatible

This is an easy to use, "just drag and drop it in your code" type of calendar for iOS. It supports both vertical and horizontal scrolling, as well as native calendar events.

Calendar Screenshot

Requirements

  • iOS 8.0+
  • XCode 9.0+
  • Swift 4.2

Installation

CocoaPods

pod 'KDCalendar', '~> 1.8.9'

Carthage

Add this to your Cartfile, and then run carthage update:

github "mmick66/CalendarView" "master"

Swift Package Manager

Go to Project -> Swift Packages and add the repository:

https://github.com/mmick66/CalendarView.git

Add this to your Package.swift:

dependencies: [
    .Package(url: "https://github.com/mmick66/CalendarView")
]

Manual

Just the files from the CalendarView/ subfolder to your project.

Setup

The calendar is a UIView and can be added either programmatically or via a XIB/Storyboard. If doing the latter, make sure that the Module is selected to be 'KDCalendar'.

IB Screenshot

It needs a delegate and data source that comply with:

protocol CalendarViewDataSource {
    func startDate() -> NSDate // UTC Date
    func endDate() -> NSDate   // UTC Date
}
protocol CalendarViewDelegate {
    func calendar(_ calendar : CalendarView, canSelectDate date : Date) -> Bool /* optional */
    func calendar(_ calendar : CalendarView, didScrollToMonth date : Date) -> Void
    func calendar(_ calendar : CalendarView, didSelectDate date : Date, withEvents events: [CalendarEvent]) -> Void
    func calendar(_ calendar : CalendarView, didDeselectDate date : Date) -> Void /* optional */
    func calendar(_ calendar : CalendarView, didLongPressDate date : Date, withEvents events: [CalendarEvent]?) -> Void /* optional */
}

The data source will provide the start date and the end date of the calendar. The methods have a default implementation that will return Date() resulting in a single-page calendar displaying the current month.

The delegate responds to events such as scrolling and the selection of specific dates.

Note: The dates should be in UTC (same as GMT)

How to Use

You would want to implement the delegate functions inside your view controller as they appear in the example project.

Say you want to be able to scroll 3 months into the past, then:

func startDate() -> Date {
    var dateComponents = DateComponents()
    dateComponents.month = -3
    let today = Date()
    let threeMonthsAgo = self.calendarView.calendar.date(byAdding: dateComponents, to: today)
    return threeMonthsAgo
}

You probably still want the calendar to open in today's date, so in this case do:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let today = Date()
    self.calendarView.setDisplayDate(today, animated: false)        
}

Say you want tomorrow to be selected for some reason:

// can be in the viewDidAppear
let today = Date()
if let tomorrow = self.calendarView.calendar.date(byAdding: tomorrowComponents, to: today) {
  self.calendarView.selectDate(tomorrow)
}

Selecting and Deselecting Dates

The calendar supports the selection of multiple dates. You can select a date either by clicking on a cell or by selecting it programmatically as:

self.calendarView.selectDate(date)

Similarly you can deselect:

self.calendarView.deselectDate(date)

You can get all the dates that were selected, either manually or programatically using:

self.calendarView.selectedDates

Layout

The calendar supports two basic layouts. Set the direction property to .horizontal or .vertical:

calendarView.direction = .horizontal

Styling

The look of this calendar can be set using the CalendarView.Style structure. There is an "out of the box" style that can be accessed statically through CalendarView.Style.Default. To change it, instantiatia a new Style object and set the variables in their desired value anywhere in your code.

override func viewDidLoad() {

    super.viewDidLoad()

    let myStyle = CalendarView.Style()
    // set your values
    calendarView.style = myStyle
}

For more information have a look at our wiki.

Marking Weekends

Some calendars will want to display weekends as special and mark them with a different text color. To do that, first set the marksWeekends variable on the calendarView itself and (optionally) define the color to use.

CalendarView.Style.cellTextColorWeekend = UIColor.red
calendarView.marksWeekends = true

IB Screenshot

The CellShape will define whether the dates are displayed in a circle or square with bevel or not.

Graying out days

If you want the days that lie outside of the rage set by startDate and endDate, you can set the color in:

CalendarView.Style.cellColorOutOfRange = UIColor(white: 0.0, alpha: 0.5)

IB Screenshot

First Day of the Week

Depending on the culture weeks are considered to start either on a Monday or on a Sunday. To change the way the days are displayed use:

CalendarView.Style.firstWeekday = .sunday

IB Screenshot

The calendar defaults to Monday which is standard in Europe.

Set locale of calendar

Set the locale for header labels of Weekdays and Month. Use:

CalendarView.Style.locale = Locale(identifier: "en_US")

IB Screenshot

The locale default is Locale.current of your device.

Custom Headers

Depending on the language, you might experience problems displaying the month strings in the header. There is however a method you can implement that will return any string you wish according to the date passed.

public protocol CalendarViewDataSource {
    /* other methods */
    func headerString(_ date: Date) -> String?
}

Events

This component has the ability to sync events from the system's EKEventStore, which is shared with the native calendar provided in iOS. This ability is optional and (in order to keep the calendar's footprint low) needs to be activated seperatly via a custom flag in the build settings as shown below:

Events Screenshot

In the "Build Settings," under the "Swift Compiler - Custom Flags" and "Active Compilation Conditions," simply add the KDCALENDAR_EVENT_MANAGER_ENABLED flag for both debug and release. The events will be enabled.

Loading Events

To load events from the system's calendar call the followint method:

self.calendarView.loadEvents()

Optionally, a complete handler can be added in case an error is returned

self.calendarView.loadEvents() { error in
    if error != nil {
        // handle error
    }
}

The code will pop up an alert view to ask the user if he will allow this app to access the calendar. If access is granted we can pass the events to the CalendarView, otherwise we get a nil and notify the app about the denial.

Creating (Adding) New Events

There is a function that allows you to add a new event in the calendar. It is currently restrictred to a single day (like the rest of the calendar)

func addEvent(_ title: String, date: Date, duration hours: NSInteger = 1) -> Bool

To detect when the user wants to add a new date, the delegate can implement the didLongPressDate method will notify the controller for a long press and the addEvent function is usually used in conjuction with this delegate method.

Currently, the example implementation of this repo will open an alert view that will prompt the user for a title to the event and set it for the duration of an hour. Custom controls could be added to further refine the selection.

As with the loading of the events we need to give persmissions to the app.

About Dates

Calculating dates can be somewhat complicated because while time is an absolute value, dates are a construct of culture: timezones are geopolitical areas and daylight savings times change according to government decision. The best way out of this is to calculate everything in UTC (same as GTM for what we are concerned) and so the startDate and endDate returned from the delegate should all be in UTC (+0000) time.

Help Needed

If you want to contribute there are always some open issues marked as enhancements in the issues tab. Any help is welcome.

Comments
  • Issue with firstWeekday. The header is not updating.

    Issue with firstWeekday. The header is not updating.

    For the CalendarView when I set the first day of the week variable to Sunday it is updating the calendar days correctly but not the header at the top.

    self.calendarView.style.firstWeekday = .sunday
    self.calendarView.style.locale = Locale(identifier: "en_US")
    

    Simulator Screen Shot - iPhone 11 - 2019-11-21 at 08 38 04

    opened by jfbomber 17
  • Logo Proposal

    Logo Proposal

    Good day @mmick66 I am a graphic designer and an open source enthusiast and i would like to contribute a logo design for your good project for free. If you will permit me, I will begin my design asap. Thanks and best regards! - Tobaloidee

    enhancement 
    opened by Tobaloidee 12
  • Date is incorrect

    Date is incorrect

    the current date based on the user's locale is incorrect beginning with the new year. When giving the current date in GMT format in the data source StartDate method, the date selected on the calendar is incorrect instead selecting the date for GMT time.

    opened by thejarlid 6
  • crash  on setDisplayDate

    crash on setDisplayDate

      public func setDisplayDate(_ date : Date, animated: Bool = false) {
            
            guard (date >= startDateCache) && (date <= endDateCache) else { return }
            self.collectionView.setContentOffset(self.scrollViewOffset(for: date), animated: animated)
            self.displayDateOnHeader(date)
        }
    
     is causing a crash 
    

    Thread 1: EXC_BAD_ACCESS (code=2, address=0x1d00399c0)

    opened by MSawalha 6
  • month-1 does nothing sometimes

    month-1 does nothing sometimes

    There is an issue when you call previous month method, sometimes it does not go to the desired month-1.

    Here is an ugly fix based on previous code..

    func setDisplayDate(_ date : Date, animated: Bool) {
    	
    	if let dispDate = self.displayDate {
    		
    		// skip is we are trying to set the same date
    		if  date.compare(dispDate) == ComparisonResult.orderedSame {
    			return
    		}
    		
    		// check if the date is within range
    		
    		if startDateCache == date {
    			return
    		}
    		if let startDateCache2 = self.calendar.date(byAdding: .month, value: -1, to: startDateCache) {
    			if  date.compare(startDateCache2) == ComparisonResult.orderedAscending {
    				return
    			}
    		}
    		else
    		{
    			if  date.compare(startDateCache) == ComparisonResult.orderedAscending {
    				return
    			}
    		}
    		
    		if  date.compare(endDateCache) == ComparisonResult.orderedDescending   {
    			return
    		}
    		
    		
    		self.collectionView.setContentOffset(
    			self.scrollViewOffset(in: self.collectionView, for: date),
    			animated: animated
    		)
    		
    	}
    	
    }
    
    /*
    func setDisplayDate(_ date : Date, animated: Bool) {
    	
    	// Julien
    	if date == startDateCache {
    		return
    	}
    	let newStartDateCache = self.calendar.date(byAdding: .month, value: -1, to: startDateCache)
    
    		
    	guard (date > newStartDateCache!) && (date < endDateCache) else { return }
    	
    	self.collectionView.setContentOffset(
    		self.scrollViewOffset(in: self.collectionView, for: date),
    		animated: animated
    	)
    	
    	self.displayDateOnHeader(date)
    	
    }
    */
    
    opened by brizzly 6
  • Starting month display

    Starting month display

    Not really an issue but a request for having an option to select the calendar display start month. So currently I have it in my app with 6 months history but at the moment the calendar starts by displaying the very first month when I would rather have it always start with the current month and then I can choose to page back 6 months.

    Is this something you could easily add to your code or have a suggestion as how best to achieve? I have played around trying to use 'scrollToItemAtIndexPath' but with no success so any help would be gratefully appreciated.

    Many thanks,

    Carl

    opened by aldertc 5
  • Feature/refactor

    Feature/refactor

    Hi!

    I've made it a bit easier to configure.

    1. If you have multiple calendars on your screen, you can style each separately
    2. Most style settings are now propagating if you set the style property even after layout
    3. Lazy loading of month info, so a million years range could be setup without any performance impact
    4. Better sync of displayDate
    5. You could now control placement of header components, or deliberately cause month label to be 0.0 height to hide it.
    6. RTL support
    7. Support for showing adjacent days
    opened by danielgindi 4
  • Programmatically selecting cells and scrolling to date don't work in viewDidLoad

    Programmatically selecting cells and scrolling to date don't work in viewDidLoad

    Calling calendarView.setDisplayDate and calendarView.selectDate in viewDidLoad, where I set up the calendarview itself doesn't do anything. Only works if I program in a delay. Am I doing something wrong, should those methods be put somewhere else?

    wontfix 
    opened by MilesV64 4
  • Incorrect Date selected?

    Incorrect Date selected?

    I have implemented the code provided and there seems to be a mismatch between the dates on the calendar and the dates selected?

    The following code:

        func calendar(_ calendar: CalendarView, didSelectDate date : Date, withEvents events: [EKEvent]) {
    
            if events.count > 0 {
                let event : EKEvent = events[0]
                print("We have an event starting at \(event.startDate) : \(event.title)")
            }
            print("Did Select: \(date) with Events: \(events.count)")
    
        }
    

    returns the following to the console when 4th July is selected?

    We have an event starting at 2016-10-09 20:25:00 +0000 : Raiders vs Chargers (Week 5) Did Select: 2016-07-04 00:00:00 +0000 with Events: 1

    I guess that the events array is not being fully populated so the indexes are misaligned. Any idea what may cause this?

    opened by RNUK 4
  • Resolving an issue where certain sizes of calendar view caused poor month offset paging

    Resolving an issue where certain sizes of calendar view caused poor month offset paging

    I just stumbled upon a size of calendar view that was causing problems when changing months due to an offset that was slightly off for certain months. This would cause pretty big issues with scrolling and cause months to be off or repeated. Feel free to merge the pull request or ignore it but I would consider utilizing the changes made to CalendarView+Delegate.swift as it does solve a rather annoying issue that I stumbled upon and took a few hours to solve.

    opened by ojseven 3
  • When would you release next version?

    When would you release next version?

    Hello, I'm using CalendarView with big appreciate.

    The latest version is 1.6.5 now, and I guess there would be an update about locale in next version. When would you update it?

    opened by kyonge 3
  • Multi date selection got a bug

    Multi date selection got a bug

    Hi, I have a scenario where the user can select multi dates(future dates) in the calendar and need to disable the selection of completed days. The issue I am facing is when I do select the future dates it is some how highlighting the previous dates (Completed one). I tried multiple ways but still no luck.

    Can any one have fix for this?

    multiselect

    Thanks in advance.

    opened by rakeshpalivela 0
  • With iOS 15 - the selected border and color don't seem to be working

    With iOS 15 - the selected border and color don't seem to be working

    The selected color doesn't seem to be working in iOS 15. ` self.calendarView = CalendarView()

        self.calendarView.backgroundColor = UIColor.white  
      
        self.calendarView.delegate = self
    
        self.calendarView.dataSource = self
    
        self.calendarView.direction = .horizontal
    
        self.calendarView.multipleSelectionEnable = false
    
        self.calendarView.setDisplayDate(Date())
    
        self.calendarView.marksWeekends = false
    
        self.calendarView.style.cellSelectedBorderColor = .red
    
        self.calendarView.style.cellSelectedColor = .green
    
        self.calendarView.style.cellSelectedTextColor = .green
    

    `

    opened by jfbomber 19
  • failing while pod install

    failing while pod install

    Installing KDCalendar (1.8.9)

    [!] Error installing KDCalendar [!] /usr/bin/git clone https://github.com/mmick66/CalendarView.git /var/folders/_d/h20wwfcx12q4lf8c1t0gs6f40000gn/T/d20210824-4675-lz4291 --template= --single-branch --depth 1 --branch 1.8.9

    Cloning into '/var/folders/_d/h20wwfcx12q4lf8c1t0gs6f40000gn/T/d20210824-4675-lz4291'... fatal: unable to access 'https://github.com/mmick66/CalendarView.git/': Failed to connect to github.com port 443: Operation timed out

    opened by ShankarSpringML 0
  • Code initialization problem

    Code initialization problem

    Version 1.9.8 is added to the view via initframe and the display is blank

    var calendarView = CalendarView(frame: CGRect(x: 20, y: 20, width: 400, height: 300))
     addSubview(calendarView)
    
    opened by Geoege-xll 0
Owner
Michael Michailidis
iOS + Node.js = ❤
Michael Michailidis
A declarative, performant, iOS calendar UI component that supports use cases ranging from simple date pickers all the way up to fully-featured calendar apps.

HorizonCalendar A declarative, performant, calendar UI component that supports use cases ranging from simple date pickers all the way up to fully-feat

Airbnb 2.2k Jan 4, 2023
Simple customizable calendar component in Swift :calendar:

Koyomi Koyomi is a simple calendar view framework for iOS, written in Swift ?? Content Features Demo App Usage introduction : Change displayed month,

Shohei Yokoyama 741 Dec 24, 2022
Malendar is a personal calendar app that connects to your default calendar and lets you add/delete events

Malendar is a personal calendar app that connects to your default calendar and lets you add/delete events. It will gather events from your default iOS calendar.

Chase 194 Jan 4, 2023
An Easy to Use Calendar for iOS (Swift 5.0)

This is an easy to use, "just drag and drop it in your code" type of calendar for iOS. It supports both vertical and horizontal scrolling, as well as

Michael Michailidis 525 Dec 23, 2022
An easy to use SwiftUI date picker for Shamsi (Persian) calendar

ShamsiDatePicker An easy-to-use SwiftUI iOS/watchOS date picker for Shamsi (Persian) calendar. Features Pure (100%) SwiftUI implementation Full suppor

Seyyed Parsa Neshaei 20 Nov 24, 2022
📅 Calendar for iOS, iPadOS and macOS in Swift

CalendarKit CalendarKit is a Swift calendar UI library for iOS, iPadOS and Mac Catalyst. It looks similar to the Apple Calendar app out-of-the-box, wh

Richard Topchii 2.2k Jan 5, 2023
A custom visual calendar for iOS 8+ written in Swift (>= 4.0).

Overview Screenshots GIF Demo Installation Usage Architecture Version matrix Advanced API For contributors Screenshots GIF Demo Installation CocoaPods

null 3.5k Dec 24, 2022
A calendar control for iOS written in swift with mvvm pattern

ASCalendar try it on appetize Installation CocoaPods You can use CocoaPods to install ASCalendar by adding it to your Podfile: platform :ios, '8.0' us

Alberto Scampini 192 Jun 26, 2022
A fully customizable iOS calendar library, compatible with Objective-C and Swift

Table of contents Screenshots Installation Pre-knowledge Support Contact Screenshots iPhone iPad Safe Orientation Today Extension iOS8/9 iOS10 Interac

Wenchao Ding 10.2k Jan 2, 2023
CalendarApp Swift - Made a calendar app in swift, completely from scratch using UIStackView and UICollectionView

CalendarApp_Swift Made a calendar app in swift, completely from scratch using UI

Arnav Chhokra 1 Feb 4, 2022
SwiftUI Simple Calendar / Date Picker for iOS

RKCalendar RKCalendar is a SwiftUI Calendar / Date Picker for iOS. Features include: minimum and maximum calendar dates selectable, single date select

null 453 Dec 28, 2022
iOS 7+ Calendar (Date Picker) with Infinite Scrolling.

RSDayFlow iOS 7 Calendar with Infinite Scrolling. Only need 4 lines of code to set up. RSDayFlow is a slim fork of DayFlow with updates and extensions

Ruslan Skorb 844 Sep 14, 2022
An availability calendar implementation for iOS

NWCalendarView NWCalendar View is an iOS control that displays a calendar. It is perfect for appointment or availibilty selection. It allows for selec

Nicholas Wargnier 60 May 27, 2021
A customizable calendar view for iOS.

JTCalendar JTCalendar is an easily customizable calendar control for iOS. Installation With CocoaPods, add this line to your Podfile. pod 'JTCalendar'

Jonathan Vukovich-Tribouharet 2.8k Dec 27, 2022
📆 An elegant calendar control for iOS.

NO LONGER MAINTAINED Daysquare An elegant calendar control for iOS. Introduction Get bored with native silly UIDatePicker? You may have a try on this

Cyandev 701 Sep 9, 2022
An open source calendar framework for iOS, with support for customization, IBDesignable, Autolayout, and more.

About MBCalendarKit is a calendar control written in Objective-C with modern best practices and Swift interoperability in mind. It offers a flexible c

Moshe 563 Oct 27, 2022
A library that expresses a github contribution calendar through an array of dates. Supports iOS and macOS.

A library that expresses a github contribution calendar through an array of dates. Supports iOS and macOS.

jasu 45 Dec 20, 2022
Simplifies iOS user permission requests (location, push notifications, camera, contacts, calendar, photos, etc).

ICanHas Swift 4 library that simplifies iOS user permission requests (push notifications, location, camera, photo library, contacts, calendar). Instal

Adolfo Rodriguez 91 Jun 2, 2022
Anime Calendar's iOS App - Schedule your seasonal anime to watch!

?? Anime Calendar Anime Calendar's iOS App - Schedule your seasonal anime to watch! Currently in progress UI Uses Xibs and some programmatic views. De

Leonardo 11 Jan 1, 2023