Custom calendar for iOS
In this article, i will guide you step by step on how to integrate and customise calendar in your app. Most of the time, designers give you custom designed calendar, and gets approved it by clients. Later on, you find yourself struck with limitation of calendar, so here is a tutorial for you to implement almost any design for your calendar.
Pre-requisites:
1) Basic knowledge of xcode and delegates.
2) Basic knowledge of pods integration.
Step 1: We will create a demo project for this tutorial.
Open xcode on your mac, and create a new project.
I named thi project as 'DemoCalendar', you can name it whatever you want to.
Step 2: Integrating JTCalendar Library via pods.
First, we initialise pod for the project. For this, open terminal and get into your project directory. Before doing this, close XCode, and then open terminal.
To initialise pods, run 'pod init' command, without quotes.
After that you will see pod file in your project directory, as shown below, open this 'podfile' in textedit:
Once it's open, paste 'pod 'JTCalendar', '~> 2.0' under target. As shown in image below.
We are half way done with integrating library, now we just need to open terminal again, and run 'pod install' command in your project directory.
We integrated the library via pods, now we open .xcworkspace project from directory.Please note you need to open .xcworkspace and not .xcodeproj now.
Step 4: Using JTCalendar Library in our demo app to display calendar.
You have ViewController.h and .m file by default in demo project. So we will use this same controller to display calendar, for your production app, you need to do this below code in your controller where you want to show the calendar.
We will import JTCalendar, it's delegate , a calendar manager which will manage the calendar and two IBOutlets for displaying calendar.
#import <UIKit/UIKit.h> #import <JTCalendar/JTCalendar.h> @interface ViewController : UIViewController<JTCalendarDelegate> @property (weak, nonatomic) IBOutlet JTCalendarMenuView *calendarMenuView; @property (weak, nonatomic) IBOutlet JTHorizontalCalendarView *calendarContentView; @property (strong, nonatomic) JTCalendarManager *calendarManager;
@end
This is how, ViewController.h will look like, after you import and declare IBOutlets for JTCalendar.
1) JTCalendarMenuView - The top view displaying month, it's interactive.
2) JTHorizontalCalendarView - Main Calendar View displaying dates. (Horizontal calendar will show next or previous month on horizontal scroll, you can use Vertical Calendar View if you want to use vertical scroll for next or previous month.)
3) JTCalendarDelegate - Like other delegates, with callbacks when user taps on date, or select a range of dates.
4) JTCalendarManager - Manages Views.
Let's move to ViewController.m file, and get our hands a little dirty :) , although the code is not so complex, but for your date selection algo, you will need to do it yourself. That is a part i am not covering in this tutorial, as i do not know how you want to use the calendar.
First synthesize the objects we created in .h file
#import "ViewController.h" @interface ViewController () @end @implementation ViewController @synthesize calendarManager,calendarMenuView,calendarContentView; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view.
}
Now, we do some coding for calendar, in viewDidLoad , copy and paste below code, it will look like this:
- (void)viewDidLoad { [super viewDidLoad]; calendarManager = [JTCalendarManager new]; calendarManager.delegate = self; [calendarManager setMenuView:calendarMenuView]; [calendarManager setContentView:calendarContentView]; [calendarManager setDate:[NSDate date]]; // Do any additional setup after loading the view.
}
Here, we are initialising calendar manager first, then we are setting it's delegate. Rest 3 lines are self explanatory, we are setting menu view, content view and setting current date for initial display.
Now, we override delegate function 'prepareDayView' of JTCalendar. This function is responsible to display date, highlight them etc. Consider this equivalent to cellForRowAtIndexPath of UITableView.
- (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView { dayView.hidden = NO; // Test if the dayView is from another month than the page // Use only in month mode for indicate the day of the previous or next month if([dayView isFromAnotherMonth]){ dayView.hidden = YES; } // Today else if([calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){ dayView.circleView.hidden = NO; dayView.circleView.backgroundColor = [UIColor blueColor]; dayView.dotView.backgroundColor = [UIColor whiteColor]; dayView.textLabel.textColor = [UIColor whiteColor]; }else{ dayView.circleView.hidden = YES; dayView.dotView.backgroundColor = [UIColor redColor]; dayView.textLabel.textColor = [UIColor blackColor]; }
}
Here, we are highlighting current date, displaying circle behind the date, you can change it's colour, hide this , chenge date text color etc.
There is another subview, dotview, which you can use to tell user if there is an event on that date. Like a notification red dot, to use that you can use it like below:
dayView.dotView.backgroundColor = [UIColor yellowColor];
[dayView.dotView setHidden:NO];
Same way you can change the colour of this dot view or hide it for date.
Lastly, do something when user taps on date or select date range. To do this we override another function didTouchDayView , consider it equivalent to didSelectRowAtIndexPath of UITableView.
- (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView { // Use to indicate the selected date NSDate *dateSelected = dayView.date; // Animation for the circleView dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); [UIView transitionWithView:dayView duration:.3 options:0 animations:^{ dayView.circleView.transform = CGAffineTransformIdentity; [self->calendarManager reload]; } completion:nil]; // Load the previous or next page if touch a day from another month if(![calendarManager.dateHelper date:calendarContentView.date isTheSameMonthThan:dayView.date]){ if([calendarContentView.date compare:dayView.date] == NSOrderedAscending){ [calendarContentView loadNextPageWithAnimation]; } else{ [calendarContentView loadPreviousPageWithAnimation]; } }
}
This is self explanatory, still i will explain it in brief:
1) dateSelected object, is the NSDate object which user selected.
2) Next code of block will perform animation on CircleView, if you want to hightlight the date on touch. This will show a circle in background, you can change colour for circle too here, or dotview as well.
3) Next is to automatically move to next month, if user selects date from next month or previous month if user taps on date from previous month.
Now, let's go to your storyboard and add two UIViews and change it's class to JTHorizontalCalendarView, and JTCalendarMenuView. As shown below.
Connect IBOutlet with these Objects in storyboard, and run the app.
Download Demo Project: https://drive.google.com/file/d/1PeTeVMNzxJVbkUIDhjKAXoNaZKfLRh2j/view?usp=sharing