This quick start tutorial demonstrates how to create a simple iOS application with TKCalendar
.
This article assumes that you have followed the Downloading UI for iOS, Installing UI for iOS and Setting Up the project steps from the common Getting Started article.
Since iOS 10, Apple requires explicit description when NSCalendar is being used, more precisely when one is trying to access the phone's calendar events. This description is prompted to the user, only when there is an attempt for accessing events, and requires user's confirmation.
If you are using TelerikUI but never accessing device's calendar your users won't get prompted with this message.
In order to submit your application to the AppStore make sure to include a NSCalendarsUsageDescription
variable to your info.plist and provide some description, for example "This application need to acces your calendar events."
Now that our project is created and the TelerikUI.framework is added, we can start referencing and using the TelerikUI types:
Open your ViewController.m
file and add a reference to Telerik UI header file:
#import <TelerikUI/TelerikUI.h>
Note that starting with Xcode 6 Apple doesn't generate the precompiled headers file automatically. That is why you should add import the UIKit framework before importing TelerikUI:
#import <UIKit/UIKit.h>
If you are writing Swift, add the same line in your bridging header.
Type the following code in viewDidLoad
method:
TKCalendar *calendarView = [[TKCalendar alloc] initWithFrame:self.view.bounds];
calendarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:calendarView];
let calendarView = TKCalendar(frame: self.view.bounds)
calendarView.autoresizingMask = UIViewAutoresizing(rawValue:UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
self.view.addSubview(calendarView)
TKCalendar calendarView = new TKCalendar (this.View.Bounds);
calendarView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
this.View.AddSubview (calendarView);
This code creates a new instance of TKCalendar
and adds it as a subview of the ViewController's main view. The autoresizingMask
property is set in order to allow correct resizing of the calendar when the device is rotated in landscape mode.
The next step is to create some random data that will be consumed by the calendar. You can use the following code:
TKCalendarEvent *event = [TKCalendarEvent new];
NSMutableArray *array = [NSMutableArray new];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];
for (int i = 0; i<3; i++) {
event.title = @"Sample event";
event.allDay = YES;
NSDateComponents *components = [calendar components:NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:date];
components.day = arc4random()%50;
event.startDate = [calendar dateFromComponents:components];
event.endDate = [calendar dateFromComponents:components];
event.eventColor = [UIColor redColor];
[array addObject:event];
}
self.events = array;
let array = NSMutableArray();
let calendar = Calendar.current
let date = Date()
for _ in 0..<3 {
let event = TKCalendarEvent()
event.title = "Sample event"
var components = (self.calendarView.calendar as NSCalendar).components(NSCalendar.Unit(rawValue:NSCalendar.Unit.year.rawValue | NSCalendar.Unit.month.rawValue | NSCalendar.Unit.day.rawValue), from: date)
components.day = Int(arc4random() % 50)
event.startDate = calendar.date(from: components)!
event.endDate = calendar.date(from: components)!
event.eventColor = UIColor.red
self.events.add(event)
}
self.events = array;
events = new List<TKCalendarEvent> ();
NSCalendar calendar = new NSCalendar (NSCalendarType.Gregorian);
NSDate date = NSDate.Now;
Random r = new Random ();
for (int i = 0; i < 3; i++) {
TKCalendarEvent ev = new TKCalendarEvent ();
ev.Title = "Sample event";
NSDateComponents components = calendar.Components (NSCalendarUnit.Day | NSCalendarUnit.Month | NSCalendarUnit.Year, date);
components.Day = r.Next () % 20;
ev.StartDate = calendar.DateFromComponents (components);
ev.EndDate = calendar.DateFromComponents (components);
ev.EventColor = UIColor.Red;
events.Add (ev);
}
This code will add 10 events with random dates to an array named events
. The arc4random
method is being used to create the random dates. The code also assigns a title and a color to the events.
Now let's add this random data to the calendar and present it. In order to do this, we should first adopt the TKCalendarDataSource
protocol:
@interface CalendarDocsWithSimpleEvent() <TKCalendarDataSource, TKCalendarDelegate>
class CalendarDocsWithSimpleEvent: TKExamplesExampleViewController, TKCalendarDataSource, TKCalendarDelegate {
class CalendarDataSource : TKCalendarDataSource
And we should implement its calendar:eventsForDate:
method:
- (NSArray *)calendar:(TKCalendar *)calendar eventsForDate:(NSDate *)date
{
NSDateComponents *components = [self.calendarView.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:date];
components.hour = 23;
components.minute = 59;
components.second = 59;
NSDate *endDate = [self.calendarView.calendar dateFromComponents:components];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(startDate <= %@) AND (endDate >= %@)", endDate, date];
return [self.events filteredArrayUsingPredicate:predicate];
}
func calendar(_ calendar: TKCalendar, eventsFor date: Date) -> [Any]? {
var components = (self.calendarView.calendar as NSCalendar).components(NSCalendar.Unit(rawValue:NSCalendar.Unit.year.rawValue | NSCalendar.Unit.month.rawValue | NSCalendar.Unit.day.rawValue), from: date)
components.hour = 23
components.minute = 59
components.second = 59
let endDate = self.calendarView.calendar.date(from: components)
let predicate = NSPredicate(format: "(startDate <= %@) AND (endDate >= %@)", endDate! as CVarArg, date as CVarArg)
return self.events.filtered(using: predicate) as [AnyObject]?
}
public TKCalendarEventProtocol[] EventsForDate (TKCalendar calendar, NSDate date)
{
NSDateComponents components = calendar.Calendar.Components (NSCalendarUnit.Day | NSCalendarUnit.Month | NSCalendarUnit.Year, date);
components.Hour = 23;
components.Minute = 59;
components.Second = 59;
NSDate endDate = calendar.Calendar.DateFromComponents (components);
List<TKCalendarEventProtocol> filteredEvents = new List<TKCalendarEventProtocol> ();
for (int i = 0; i < this.events.Count; i++) {
TKCalendarEventProtocol ev = this.events[i];
if (ev.StartDate.SecondsSinceReferenceDate <= endDate.SecondsSinceReferenceDate &&
ev.EndDate.SecondsSinceReferenceDate >= date.SecondsSinceReferenceDate) {
filteredEvents.Add (ev);
}
}
return filteredEvents.ToArray ();
}
Here, the predicate is used to filter the events array by date. Do not forget to assign the dataSource
property of TKCalendar
:
calendarView.dataSource = self;
calendarView.dataSource = self
calendarView.DataSource = new CalendarDataSource (this);
For information about populating TKCalendar
with EventKit events, please refer to the following article: Populating with data
As a next step you may want to tune up the calendar more precisely by specifying minimum and maximum allowed dates. This can be done by setting the minDate
and maxDate
properties:
calendarView.minDate = [TKCalendar dateWithYear:2010 month:1 day:1 withCalendar:nil];
calendarView.maxDate = [TKCalendar dateWithYear:2016 month:12 day:31 withCalendar:nil];
calendarView.minDate = TKCalendar.date(withYear: 2010, month: 1, day: 1, with: nil)
calendarView.maxDate = TKCalendar.date(withYear: 2016, month: 12, day: 31, with: nil)
calendarView.MinDate = TKCalendar.DateWithYear (2010, 1, 1, calendar);
calendarView.MaxDate = TKCalendar.DateWithYear (2016, 12, 31, calendar);
By default, TKCalendar
displays the current date, use the navigateToDate:animated
method to display a different date:
NSDateComponents *components = [NSDateComponents new];
components.year = 2016;
components.month = 6;
components.day = 1;
NSDate *newDate = [self.calendarView.calendar dateFromComponents:components];
[self.calendarView navigateToDate:newDate animated:NO];
var components = DateComponents()
components.year = 2016
components.month = 6
components.day = 1
let newDate = self.calendarView.calendar.date(from: components)
calendarView.navigate(to: newDate!, animated: false)
NSDateComponents newComponents = new NSDateComponents();
newComponents.Year = 2015;
newComponents.Month = 5;
newComponents.Day = 1;
NSDate newDate = calendarView.Calendar.DateFromComponents (newComponents);
calendarView.NavigateToDate (newDate, true);
TKCalendar
sends different notifications. For example, in order to be notified when a date was selected, override the calendar:didSelectDate:
method of TKCalendarDelegate
protocol:
- (void)calendar:(TKCalendar *)calendar didSelectDate:(NSDate *)date
{
NSLog(@"%@", date);
}
func calendar(_ calendar: TKCalendar, didSelect date: Date) {
print("%@", date)
}
class CalendarDelegate : TKCalendarDelegate
{
public override void DidSelectDate (TKCalendar calendar, NSDate date)
{
Console.WriteLine ("{0}", date);
}
}
Note that TKCalendar
supports single, multiple and range date selection. Selection modes are described in detail in the article about Selection.
Along with selection notifications TKCalendar
supports navigation and customization notifications by adopting the TKCalendarDelegate
protocol. These notifications are described in the articles about: Navigation and Customizations.
Here is the full code of this example:
#import "CalendarDocsWithSimpleEvent.h"
#import <TelerikUI/TelerikUI.h>
@interface CalendarDocsWithSimpleEvent() <TKCalendarDataSource, TKCalendarDelegate>
@property (nonatomic, strong) NSArray *events;
@property (nonatomic, strong) TKCalendar *calendarView;
@end
@implementation CalendarDocsWithSimpleEvent
- (void)viewDidLoad
{
[super viewDidLoad];
TKCalendar *calendarView = [[TKCalendar alloc] initWithFrame:self.view.bounds];
calendarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:calendarView];
calendarView.delegate = self;
calendarView.dataSource = self;
calendarView.minDate = [TKCalendar dateWithYear:2010 month:1 day:1 withCalendar:nil];
calendarView.maxDate = [TKCalendar dateWithYear:2016 month:12 day:31 withCalendar:nil];
self.calendarView = calendarView;
TKCalendarEvent *event = [TKCalendarEvent new];
NSMutableArray *array = [NSMutableArray new];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];
for (int i = 0; i<3; i++) {
event.title = @"Sample event";
event.allDay = YES;
NSDateComponents *components = [calendar components:NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:date];
components.day = arc4random()%50;
event.startDate = [calendar dateFromComponents:components];
event.endDate = [calendar dateFromComponents:components];
event.eventColor = [UIColor redColor];
[array addObject:event];
}
self.events = array;
NSDateComponents *components = [NSDateComponents new];
components.year = 2016;
components.month = 6;
components.day = 1;
NSDate *newDate = [self.calendarView.calendar dateFromComponents:components];
[self.calendarView navigateToDate:newDate animated:NO];
[self.calendarView reloadData];
}
#pragma mark TKCalendarDataSource
- (NSArray *)calendar:(TKCalendar *)calendar eventsForDate:(NSDate *)date
{
NSDateComponents *components = [self.calendarView.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:date];
components.hour = 23;
components.minute = 59;
components.second = 59;
NSDate *endDate = [self.calendarView.calendar dateFromComponents:components];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(startDate <= %@) AND (endDate >= %@)", endDate, date];
return [self.events filteredArrayUsingPredicate:predicate];
}
#pragma mark TKCalendarDelegate
- (void)calendar:(TKCalendar *)calendar didSelectDate:(NSDate *)date
{
NSLog(@"%@", date);
}
@end
import Foundation
class CalendarDocsWithSimpleEvent: TKExamplesExampleViewController, TKCalendarDataSource, TKCalendarDelegate {
let calendarView = TKCalendar();
var events = NSMutableArray();
override func viewDidLoad() {
super.viewDidLoad()
let calendarView = TKCalendar(frame: self.view.bounds)
calendarView.autoresizingMask = UIViewAutoresizing(rawValue:UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
self.view.addSubview(calendarView)
calendarView.delegate = self
calendarView.dataSource = self
calendarView.minDate = TKCalendar.date(withYear: 2010, month: 1, day: 1, with: nil)
calendarView.maxDate = TKCalendar.date(withYear: 2016, month: 12, day: 31, with: nil)
let array = NSMutableArray();
let calendar = Calendar.current
let date = Date()
for _ in 0..<3 {
let event = TKCalendarEvent()
event.title = "Sample event"
var components = (self.calendarView.calendar as NSCalendar).components(NSCalendar.Unit(rawValue:NSCalendar.Unit.year.rawValue | NSCalendar.Unit.month.rawValue | NSCalendar.Unit.day.rawValue), from: date)
components.day = Int(arc4random() % 50)
event.startDate = calendar.date(from: components)!
event.endDate = calendar.date(from: components)!
event.eventColor = UIColor.red
self.events.add(event)
}
self.events = array;
var components = DateComponents()
components.year = 2016
components.month = 6
components.day = 1
let newDate = self.calendarView.calendar.date(from: components)
calendarView.navigate(to: newDate!, animated: false)
self.calendarView.reloadData();
}
func calendar(_ calendar: TKCalendar, eventsFor date: Date) -> [Any]? {
var components = (self.calendarView.calendar as NSCalendar).components(NSCalendar.Unit(rawValue:NSCalendar.Unit.year.rawValue | NSCalendar.Unit.month.rawValue | NSCalendar.Unit.day.rawValue), from: date)
components.hour = 23
components.minute = 59
components.second = 59
let endDate = self.calendarView.calendar.date(from: components)
let predicate = NSPredicate(format: "(startDate <= %@) AND (endDate >= %@)", endDate! as CVarArg, date as CVarArg)
return self.events.filtered(using: predicate) as [AnyObject]?
}
func calendar(_ calendar: TKCalendar, didSelect date: Date) {
print("%@", date)
}
}
public class CalendarDocsWithSimpleEvent : XamarinExampleViewController
{
CalendarDelegate calendarDelegate;
List<TKCalendarEvent> events;
public TKCalendar CalendarView {
get;
set;
}
public TKCalendarEventProtocol[] EventsForDate {
get;
set;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
TKCalendar calendarView = new TKCalendar (this.View.Bounds);
calendarView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
this.View.AddSubview (calendarView);
calendarDelegate = new CalendarDelegate ();
calendarView.DataSource = new CalendarDataSource (this);
events = new List<TKCalendarEvent> ();
NSCalendar calendar = new NSCalendar (NSCalendarType.Gregorian);
NSDate date = NSDate.Now;
Random r = new Random ();
for (int i = 0; i < 3; i++) {
TKCalendarEvent ev = new TKCalendarEvent ();
ev.Title = "Sample event";
NSDateComponents components = calendar.Components (NSCalendarUnit.Day | NSCalendarUnit.Month | NSCalendarUnit.Year, date);
components.Day = r.Next () % 20;
ev.StartDate = calendar.DateFromComponents (components);
ev.EndDate = calendar.DateFromComponents (components);
ev.EventColor = UIColor.Red;
events.Add (ev);
}
calendarView.MinDate = TKCalendar.DateWithYear (2010, 1, 1, calendar);
calendarView.MaxDate = TKCalendar.DateWithYear (2016, 12, 31, calendar);
// calendarDelegate.events = this.events;
calendarView.Delegate = calendarDelegate;
NSDateComponents newComponents = new NSDateComponents();
newComponents.Year = 2015;
newComponents.Month = 5;
newComponents.Day = 1;
NSDate newDate = calendarView.Calendar.DateFromComponents (newComponents);
calendarView.NavigateToDate (newDate, true);
calendarView.ReloadData();
}
class CalendarDataSource : TKCalendarDataSource
{
CalendarDocsWithSimpleEvent main;
public List<TKCalendarEvent> events;
public CalendarDataSource(CalendarDocsWithSimpleEvent main)
{
this.main = main;
}
public TKCalendarEventProtocol[] EventsForDate (TKCalendar calendar, NSDate date)
{
NSDateComponents components = calendar.Calendar.Components (NSCalendarUnit.Day | NSCalendarUnit.Month | NSCalendarUnit.Year, date);
components.Hour = 23;
components.Minute = 59;
components.Second = 59;
NSDate endDate = calendar.Calendar.DateFromComponents (components);
List<TKCalendarEventProtocol> filteredEvents = new List<TKCalendarEventProtocol> ();
for (int i = 0; i < this.events.Count; i++) {
TKCalendarEventProtocol ev = this.events[i];
if (ev.StartDate.SecondsSinceReferenceDate <= endDate.SecondsSinceReferenceDate &&
ev.EndDate.SecondsSinceReferenceDate >= date.SecondsSinceReferenceDate) {
filteredEvents.Add (ev);
}
}
return filteredEvents.ToArray ();
}
}
class CalendarDelegate : TKCalendarDelegate
{
public override void DidSelectDate (TKCalendar calendar, NSDate date)
{
Console.WriteLine ("{0}", date);
}
}
}
You can easily change the way data is presented in chart by changing the view mode property:
self.calendarView.viewMode = TKCalendarViewModeYear;
self.calendarView.viewMode = TKCalendarViewMode.year
this.CalendarView.ViewMode = TKCalendarViewMode.Year;
All view modes are desctibed in the following article:
View modes