Thursday, April 9, 2009

iPhone Development: Creating Native Calendar Like View

In this post I will be creating a calendar, which could reused in an any native application.
I used the calendar source from here and modified it a little bit to suit my requirements.
You can find the modified code from my project here: DOWNLOAD PROJECT
The final screen should look like this:

You can download the complete project from the link given, I will only discuss how we can reuse this calendar and modify it to fit our specific requirements.
Open the project CalendarTest in xCode. You will find a folder Calendar containing some 20 files.
You can reuse this folder as such in any project you want show the calendar. I will be using these files to display a modified calendar in CalendarTestView header and implementation files.

Open CalendarTestView.m and find the following code:

- (void)loadView {

[super loadView];

calendarView = [[[KLCalendarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 360) delegate:self] autorelease];

myTableView = [[UITableView alloc]initWithFrame:CGRectMake(0,260,320,160) style:UITableViewStylePlain];

myTableView.dataSource = self;

myTableView.delegate = self;

UIView *myHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0,0,myTableView.frame.size.width , 20)];

myHeaderView.backgroundColor = [UIColor grayColor];

[myTableView setTableHeaderView:myHeaderView];

[self.view addSubview:myTableView];

[self.view addSubview:calendarView];

[self.view bringSubviewToFront:myTableView];

}


Here I have initialized a tableView and the calendarView with appropriate frames. You can change the frames if you want to change the respective size of tableView and/or calendarView.

Now find the Calendar Delegate methods:

- (void)calendarView:(KLCalendarView *)calendarView tappedTile:(KLTile *)aTile{

NSLog(@"Date Selected is %@",[aTile date]);

[aTile flash];

if(tile == nil)

tile = aTile;

else

[tile restoreBackgroundColor];

tile = aTile;

}



Here you need to write the code that should be executed when a tile is tapped. Typical usage of this method would be to load data for the tableView from database corresponding to the date of the tile.

- (KLTile *)calendarView:(KLCalendarView *)calendarView createTileForDate:(KLDate *)date{

CheckmarkTile *tile = [[CheckmarkTile alloc] init];

//tile.checkmarked = YES;//based on any condition you can checkMark a tile

return tile;

}


This method is called for each tile. Just like cellForRow is called for each cell. Please note that although this method will not be called more than once for a tile, but when you change the month of calendar, all tiles are redrawn, so this method will again be called for each tile.
You can find a commented line in this method! This is very important code which you can use to tell the user that they have some data corresponding to a date.
For example I have a meeting on 4th of current month. You can check if tile.date == 4th then check-mark the tile.

- (void)didChangeMonths{

UIView *clip = calendarView.superview;

if (!clip)

return;

CGRect f = clip.frame;

NSInteger weeks = [calendarView selectedMonthNumberOfWeeks];

CGFloat adjustment = 0.f;

switch (weeks) {

case 4:

adjustment = (92/321)*360+30;

break;

case 5:

adjustment = (46/321)*360;

break;

case 6:

adjustment = 0.f;

break;

default:

break;

}

f.size.height = 360 - adjustment;

clip.frame = f;

CGRect f2 = CGRectMake(0,260-adjustment,320,160+adjustment);

myTableView.frame = f2;

[self.view bringSubviewToFront:myTableView];

tile = nil;

}


This method is called every time you change the month in calendar. I have done some adjustments for fixing the free space between tableView and calendar when there are less number of weeks in a month. You can wrote your own logic for that.


Now the tableView delegate methods. You can write anything you want depending on your requirement. I have written some dummy code to take screen shots

#pragma mark tableViewDelegate Methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 1;

}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return 5;

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *MyIdentifier = @"MyIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];

}

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

[cell setText:@"No Data For Now"];

return cell;

}


You can read data from the source which maintains data according to the last tile tapped.

Let me know if I am missing something.

17 comments:

  1. Thanks a lot for this tutorial. Great work

    ReplyDelete
  2. hihi, im new in imac programming. Just to check with you, what would be the code if I would like to highlight a specific range of date in the calendar? For example, from 4th June 2009-28th June 2009 I would like to highlight it and set the cell at "No data for now" as School Holidays.. Could you guide me on how to do it? Thanks alot! (:

    ReplyDelete
  3. Like you approach.
    I need a simple custom calendar developed.
    Let me know if you are interested.

    jP

    ReplyDelete
  4. TherasoftOnline,

    you can send over the details on my email: ved.redjack@gmail.com

    ReplyDelete
  5. can't download the CalenderTest.zip file. Can you post it again?

    ReplyDelete
  6. @above: I just confirmed, download link is working...can you check again?

    ReplyDelete
  7. Hi Ved I really apprecaite this post. I am also an Iphone developer, and looking to create some custom controls, as making Round Rect button in 75degree angle, and slice and use it in such manner that i won't occupy much space.

    I new this command for making custom button as CGRectMake:(x,y,width, height), now how make a pentagonal button with UIKit.h

    ReplyDelete
  8. Hi Umaid,
    You can make an image of any shape you want and use [button setImage: forState:]
    try playing with it, I have used it almost everytime I needed a custom shape button.

    ReplyDelete
  9. please tell me those function where i change the tile color and if i want to set the tile image then kindly tell me...

    please tell me exact class and function where i would change the tile's

    ReplyDelete
  10. What a great post, I actually found it very thought provoking, thanks iphone

    ReplyDelete
  11. Nice Topic about IPhone.
    I would also like to share iphone application development topic. i hope you all guys found some usefull information.

    ReplyDelete
  12. Beautifully explored. web development companies are offering custom iPhone application development to put your ideas into existence.

    iphone developer

    ReplyDelete
  13. Hello,
    Nice blog i like it
    This will help communicate with your developer and make things run smoother.

    Hire iphone Developer

    ReplyDelete
  14. Hi, I use this code for my project for ipad, but as I go to next or previous month calendar dimension automatically change. I have read whole calendar code but nothing get.

    ReplyDelete
  15. if you dont need to change the dimensions, just do nothing inside the didChangeMonths() method

    ReplyDelete
  16. Hey is the project for MAC OSX.
    I thought it would be for Iphone!?

    ReplyDelete

Leave your suggestions