In this post I will be creating a calendar, which could reused in an any native application.
- (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];
}
- (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;
}
- (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;
}
- (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;
}
#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;
}


[...] Calendar [...]
when i open it in xcode it works. when i copy it into my project (calendar folder) it gives me error
duplicate symbol _main
ok, pls disregard. found that main.m was copied to calendar folder for some reason via Finder. even if i did not select it
It sometimez happens..wen u mistakenly select files when adding existing files to project. may b it heppnd in ur case.
Hi
Great tutorial. Its was biggest hurdle for iphone developers using a calendar. This tutorial helped a lot in directly implementing a calendar in a project.
I wanted to have different type of calender… Like a day view calendar
This is the image url of what i am trying to say:
http://www.kyoobed.com/applications/clockedin/iphone/images/Day-View.png
Any ideas on how to implement this.. It would be great if u can throw some light to this as most of the business applications require such kind of calenders too.
@Maulik:
the view you mentioned is much simpler. It is just a tableView with indexes.
Hi ABC,
Thanks for the quick reply.
I didnt get the exact idea of how is it a table view with indexes because I have always seen indexes at the top of each section. So it should have been like this:
10 AM:
Some text here
11 AM:
Some text here
So in this 10AM and 11AM are the indexes and “Some text here” is the data within the index
But the format here is
10 AM: Some text here
11 AM: Some text here
and so on
Even if you look closely the event if it starts at 10:15 then the coloured box is also drawn below the mark of 10:00 AM
I hope you are getting what I am trying to explain.
It would be great if you could show some coding example or at least some way to achieve this. I would be very obliged to you if you show me some way.
Thank you ABC.
Hi Maulik,
Sorry for the late reply. Yes I understand the issues you mentioned. What you can do is to create your own custom cells. You have full control over every thing then and you can layout subviews exactly the way you want.
I will write 1 example like this, but that will take some time coz m really consumed wid office works.
Let me know if you wer able to fix it.
Hi ABC,
No issues for the late reply. I am working on it and will definitely let you know once i fix it. I am not sure whether i will be able to do it or not as I am not expert like you but will definitely give hands on it.
I will be awaiting for your example too.
Meanwhile, I came across one more issue dont know whether this is the right place to post it or not, but the issue is I wanted to create a accordion style table view. What i mean is, I have a table view which has the list of cities.Once i tap on one of the cells in the table it should expand and the list below it should move down. The description and detail of the city should appear in the expanded list. If i tap again on the same cell it will collapse. I hope you got the idea that I am trying to tell you. If possible let me know any way to achieve this. I have found a project on code.google related to MAC OS X but not related to iPhone. If you want i will post the link over here. The code is very complicated and scattered.
I would like you to show some way to achieve this as this is a very immediate thing i need to accomplish.
Thanks for the reply. Awaiting for your suggestion on this. You can also mail me on bcod.maulik@gmail.com
Hi ABC,
No issues for the late reply. I am working on it and will definitely let you know once i fix it. I am not sure whether i will be able to do it or not as I am not expert like you but will definitely give hands on it.
I will be awaiting for your example too.
Meanwhile, I came across one more issue dont know whether this is the right place to post it or not, but the issue is I wanted to create a accordion style table view. What i mean is, I have a table view which has the list of cities.Once i tap on one of the cells in the table it should expand and the list below it should move down. The description and detail of the city should appear in the expanded list. If i tap again on the same cell it will collapse. I hope you got the idea that I am trying to tell you. If possible let me know any way to achieve this. I have found a project on code.google related to MAC OS X but not related to iPhone. If you want i will post the link over here. The code is very complicated and scattered.
I would like you to show some way to achieve this as this is a very immediate thing i need to accomplish.
Thanks for the reply. Awaiting for your suggestion on this
Hi Maulik,
The seond issue you mentioned is quite easy. All you have to do is INSERT records between a transaction which starts with
[tableView beginUpdates] and ends with [tableView endUpdates].
Will paste an example code today by evening.
Gr8
Awaiting for your example code. Thank you very much for all the pain and time you are giving to resolve such issues.
Hi Maulik, Sorry for getting late:
For dynamically inserting rows you do this:
[myTableView beginUpdates];
[myTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
[myTableView deleteRowsAtIndexPaths:indexPaths2 withRowAnimation:UITableViewRowAnimationTop];
[myTableView endUpdates];
Now lets assume in your case: You have an array of cities called “cities”. and you have a dictionary that holds an array of data for every city. I suppose this is the data that will be displayed against a city when it is tapped.
Now you will have to keep track of the status of each cell. Wether it is already expanded or it is in compressed form. So you make an array called mainCellStatus and initialize it like this:
for(int i=0; i<[cities count]; i++)
[mainCellStatus addObject@"compressed"]; //since all cells are compressed in beginning. Note that u shud actually make an array of integer rather den strings…
So your tableView Delegate methods should look like this
numberOfSections .. { return [cities count]; } // this is obvious..u r making as many sections as number of cities.
-(NSInteger)numberOfRowsInSection:(NSInteger)section //this 1 s a lil tricky
{
//check if the section is in compressed state or not
if([[status objectAtIndex:section] isEqualToString:@"compressed"])
return 1; //coz in compressed state only the city will be displayed
else{
//we need to get the corresponiding array of data first
NSString *city = [cities objectAtIndex: section];
NSArray *arrayForThisCity = [dictionary objectForKey: city];
return 1+[arrayForThisCity count]; // have added 1 because number of rows in that section should be 1(City) + n(number of data elements for that city);
}
Ok Now the cellForRow method!
//this is simple just check the cell is first row of section or not.
if(indexPath.row == 0)
cell.text = [cities objectAtIndex: indexPath.section];
else
[arrayForCity objectAtIndex: indexPath.row-1]; //obtain arrayForCity like we did in prev method
Now the most tricky part! didSelect delegate method of tableView..
{
//first find if the cell tapped is the first row of the section or not. Coz you don want to compress the section if he taps on child rows of a city..
if(indexPath.row == 0)
return; //do nothing in this case
//now check if the section is compressed or expanded.
if([[ status objectAtIndex: indexPath.section] isEqualToString:@"compressed"])
{
//create indexPaths for rows to be inserted.
NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
for(int i=0;i<[arrayForThisCity count]; i++)
{
NSIndexPath *iP = [NSIndexPath indexPathForRow:(i+1) inSection:indexPath.section];
}
[myTableView beginUpdates];
[myTableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
[myTableView endUpdates];
//DONT FORGET TO MARK THE STATUS
[status replaceObjectAtIndex:indexPath.section withObject:@"expanded"];
}
similarly use this if the rows were already expanded.
[myTableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
Thanks for showing this. But One of the ways i tried and implemented was a bit or i can say far more easier than this what you showed. I have issues in this also which i will tell you later but first tell me whether this is also a good way of doing the same thing or not?
In my method i have take a static integer say “myrow”.
Now on didselectrowatIndexpath I assign the indexpath of the cell tapped to this “myrow”.
and then reload the table data. Now when i reload table data heightForRowAtIndexPath is called in which i have the following code:
if(indexPath.row == myrow)
{
return 120;
}
else
{
return 50;
}
So this increases the height of the cell that i clicked. I have placed a label in the customcell which is below the title of the cell so it will be only visible if u increase the height of the cell.Like this i can place many labels in the cell below each other but they will be visible only when the height of the cell is increased.
Again there is an issue in this: The second last and the last row of the cell shows this labels which are below it and shouldnot be visible untill you expand them. But i guess at the second last and last row the cell is utilising the area below it which is a free space.
I dont know whether i am trying the right thing or not. I will definitely try the way you have shown but since i am not very strong with the NSDictionary part i am a bit confused about that.
Do give me review about the way i showed you.
Yah the approach sounds good. I inserted/deleted new rows at run time, where as you are initializing everything at start and hiding/showing it by manipulating the height of row.
M not sure how you can fix the last row issue. I think you should read the documentation of UITableView for the fix. Or what you can do is insert a blank cell at the end.
Hi,
Great Tutorial, Im facing issues while integrating CalendarTest with my project. Im doing switch between two views from the MainViewController using buttons, Now i want to one of the Views to be Calendar, so can you tell me how can i add CalendarTest to my view and still be controlled by one MainViewController…..
Thanks in advance…
Hi ABC,
You said that making a calendar control like this is a very simple
http://www.kyoobed.com/applications/clockedin/iphone/images/Day-View.png
Can you please elaborate more on this? Or if you can make a sample of this it would be of great help. I need to implement this some how.
Anyways i made this above one. So no issues now.
Can you please guide me how to make text in cell that displaying the date to be center aligned in cell [Currently it is Left Top aligned]……Also i want to change the color, how to find the particular color RGB value…?
How would you go about selecting and deselecting a tile back to its original state color and default state? Is there a way to not have to redraw the entire calendar view? And perhaps only just the selected tile?
Is it possible to copy names from the contacts database and import them to the calendar???
Great tutorial and great code. I have one complaint or one change suggestion to make the code a little more apple compliant.
When you create a calendarView via -initWithFrame:delegate: the delegate method -didChangeMonth is called.
This is a problem because you have not returned the calendar view, so the delegate has no reference to it. Thus the delegate must add an unnecessary error check. There are many ways to change the code to fix this problem, but I believe the apple way of doing things is to change the delegate method to something like.
-calendarViewDidChangeMonths:(KLCalendarView *)calView
This is similar to how the UITableViewDelegate and UITableViewDataSource methods work
How can i add events/appoinments on calendar.
Thanks in advance!!!!
is there another link to download the project?
the one above doesn’t work
thanks
we try this code but i got 16 errors in my project which are “some classes reference not found” so plz tell me how to add calendar folder in our project and how get the reference of that folder…plz give the replay as early as possible…..
Love the work you put into this!
I have a problem where the data is being retrieved from a feed but only a month’s worth at a time. So I’ve managed to fetch the data in the didChangeMonths but the tiles are redrawn before the data is fully fetched. Is there a way to force a redraw of all the tiles?
Hi, anybody knows how to put the data from Google Calendar to this app?