iPhone Dev Sessions: How To Make An Orientation-Aware Clock

57 Comments

iphone_clock

For this tutorial we’re going to build a simple clock that is orientation-aware, meaning that when you rotate your iPhone, the time rotates with it. I’m assuming you have a basic knowledge of the iPhone SDK.

To get started, you will need a label for the time and a background image. You will also need a timer. To get started, you must declare your outlets in code before Interface Builder will be able to use them. I’ll show you how to do that now.

Let’s Get Our Hands in Some Code

Edit SimpleClockViewController.h so it looks like this:

[sourcecode language=”csharp”]

#import <UIKit/UIKit.h>

@interface SimpleClockViewController : UIViewController {
IBOutlet UILabel* clockLabel;
NSTimer *myTicker;
}

@end

[/sourcecode]

The myTicker is going to be responsible for updating the clockLabel. We will implement that code later.

The next thing you want to do is drag background_image.png to your project (see image below). You can get the image here.

image-510

You want to copy the item to the project’s directory so put a check mark next to “Copy items into destination group’s folder (if needed).” Your settings should look similar to this. Click Add.

2009-03-09_1229

Open SimpleClockViewController.xib. Drag UIImageView from the Library to the View window. This will act as a placement holder for our background image.

image-5101

Bring up the Attributes Inspector. Set the Image to background_image.png. Set the Mode to Scale To Fill so that the background_image.png stretches out when we rotate the iPhone.

2009-03-06_15431

Bring up the Size Inspector and change the Autosizing settings to look like this. The arrows in the Autosizing box act as outward springs, which cause the view to resize itself proportionally based on the width or height of its superview. The “I”s act as struts that keep a fixed distance when the View is changed when you rotate the iPhone. If that’s hard to visualize, Interface Builder has an animation to the right of the Autosizing box will help you visualize its current settings.

2009-03-06_1545

Drag a Label to the View window and resize to approximately the width of the window. Center it. This makes the time larger and also positions the time to be rotated around its center point when you turn the iPhone into landscape mode.

image-5102

Change the font of the label by selecting the Label and hitting Command-T. Change the settings so you’re using Helvetica, Bold, size 48.

2009-03-06_15561

Bring up the Attributes Inspector. Change the Layout Alignment to Center. Again, we’re doing this so the time rotates around its center. Change the font color to white so it looks good on the dark background. It should look similar to this:

2009-03-06_1557

Bring up the Size Inspector and change your Autosizing settings to look like the image below. This makes sure the time rotates and positions itself correctly around its center.

2009-03-06_1557a

Lastly, Control-Drag from File’s Owner to the Label and choose clockLabel when the outlet box pops up. This tells your Label which variable it is in the code.

2009-03-09_1311

Save and close Interface Builder. Back in Xcode, open SimpleClockViewController.h and add runTimer and showActivity methods. These declare the functions we’re going to write.

[sourcecode language=”csharp”]

#import <UIKit/UIKit.h>

@interface SimpleClockViewController : UIViewController {
IBOutlet UILabel* clockLabel;
NSTimer *myTicker;
}

/* New Methods */
– (void) runTimer;
– (void)showActivity;

[/sourcecode]

Open SimpleClockViewController.m and add the methods we just declared.

[sourcecode language=”csharp”]

– (void)runTimer {
// This starts the timer which fires the showActivity
// method every 0.5 seconds
myTicker = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: @selector(showActivity)
userInfo: nil
repeats: YES];

}

// This method is run every 0.5 seconds by the timer created
// in the function runTimer
– (void)showActivity {

NSDateFormatter *formatter =
[[[NSDateFormatter alloc] init] autorelease];
NSDate *date = [NSDate date];

// This will produce a time that looks like "12:15:00 PM".
[formatter setTimeStyle:NSDateFormatterMediumStyle];

// This sets the label with the updated time.
[clockLabel setText:[formatter stringFromDate:date]];

}

[/sourcecode]

The runTimer method only has 1 line of code split into multiple lines. All it does is call the showActivity method every 0.5 seconds.

The showActivity method formats the clockLabel so it looks like “12:15:00 PM” and sets it to the current time. As mentioned above, this method is called every 0.5 seconds.

We want to call runTimer after the view loads. This is a common method that, when Xcode generated SimpleClockViewController.m, they included a method called viewDidLoad. This method is called immediately after the View items are loaded. Find the viewDidLoad method and uncomment it.

Add [self runTimer]; to the end of the method. It should now look like this:

[sourcecode language=”csharp”]

// Implement viewDidLoad to do additional
// setup after loading the view, typically from a nib.
– (void)viewDidLoad {
[super viewDidLoad];

// This calls the runTimer method after loading
// SimpleClockViewController.xib
[self runTimer];
}

[/sourcecode]

When Xcode generated SimpleClockViewController.m, they also included shouldAutorotateToInterfaceOrientation. By default, views display only in portrait orientation, so you need to implement shouldAutorotateToInterfaceOrientation method if you want to support other orientations.

Locate the shouldAutorotateToInterfaceOrientation method and uncomment it. You can support only some orientations such as portrait or landscape with Home button on the right, but we don’t need to limit ourselves to those scenarios. We want to support all orientations so the view rotates correctly no matter how we’re holding the iPhone. To do this, replace return (interfaceOrientation == UIInterfaceOrientationPortrait); with return YES;.

[sourcecode language=”csharp”]

// Override to allow orientations other than
// the default portrait orientation.
– (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;
}

[/sourcecode]

Now you can build and run it! Hit Command-Left to see your UI rotate with the iPhone simulator. You can Build and Run the project to make sure everything is compiling and running.

57 Comments

Rob

hi i am a beginner in objective-c and would like to know if that is the way you would clean up memory:

– (void) showActivity
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
NSDate *date = [[[NSDate alloc] init] autorelease];

[formatter setTimeStyle:NSDateFormatterMediumStyle];

//change font size by orientation
int fontSize=90;
if([[UIDevice currentDevice] orientation]==UIInterfaceOrientationPortrait) fontSize=48;
clockLabel.font = [UIFont fontWithName:@”Helvetica” size:fontSize];

[clockLabel setText:[formatter stringFromDate:date]];

[pool release];
}

HASAN AYDIN

if you want to increase font size when landscape mode;

Add belove this codd
// This will produce a time that looks like “12:15:00 PM”.
[formatter setTimeStyle:NSDateFormatterMediumStyle];

//change font size by orientation
int fontSize=90;
if([[UIDevice currentDevice] orientation]==UIInterfaceOrientationPortrait) fontSize=48;
clockLabel.font = [UIFont fontWithName:@”Helvetica” size:fontSize];

Matthew

Nice clear tutorial, but I’m getting the “quits at launch” problem too. Builds fine.

Thanks!

dkk

you probably forgot to include NSTimer *myTicker; at the .h file

Taylor Blau

When I enter this line of code:
// This starts the timer which fires the showActivity
// method every 0.5 seconds
myTicker = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: @selector(showActivity)
userInfo: nil
repeats: YES];

}

It gives me a build error that myTicker is undefined.

Can anyone help me?

David

This could be because you haven’t declared the myTicker variable in the header of your viewcontroller header.

Ju

Could you send me the source code for this? I get tons of errors when I build and run. It may be because this was developed over a year ago or maybe because I don’t know what i’m doing. Let me know if you know something I don’t. Thanks so much :) Great tutorial.

Daniel Henriksson

Hi!

I’m also having a problem with the white background, other than that, thanks for the tutorial!

Trilok Ramakrishna

It is a nice tutorial.

One small change to the .h file, check the spelling of runtimer it should be runTimer.

One more thing, when you do the change to interface, save it.

Pindar Van Arman

I am getting the same blank white screen as multiple other users. What are we doing wrong?

Rich

As previous comment.

It is a nice tutorial and very clearly done and I appreciate the time taken to write these helpful descriptions. However, although it compiles and installs perfectly all that displays is a white screen – at least for me. Is it something memory related?

Andrew

Is this code valid for the 3.1.2 SDK release? Because I can not get my app to display the clock. It builds with out error it just quits after opening.

Clock Lady

I was searching on Google, for information on clocks, for a blog item I am writing, and I came across your site. Although I didn’t find the exact information i was looking for in your article, I thought I would take the time to let you know that your article has spawned another blog topic for me, I felt that this tutorial was very easy to follow which meant people of all ages and skills could make this adjust meant to their Iphone. I would certainly recommend this to anybody. Thanks Megan xx

Rajesh Rajappan

Thanks for this tutorial. One little note that i think you need to init the date object to display the time.

So the line 18 on the showActivity method should be,

NSDate *date = [[NSDate date] init];

Thanks again.

Nasser Al Zahrani

Hello
I really have no idea why you(I mean theappleblog.com) always give no attention to the memory management issue when it is very crucial in such a limited environment. your code is leaking everywhere sir.
1- you did not release the instance variables in the dealloc: .
2- you did not release *formatter.
it is really important for newbies like my self to know theses principles. and your website is targeted to general people where the programing background of the majority of them is very shallow.Right?
feel free to delete my post only if managed to fix the issues.
thanks

Allister

For some reason, when I run in the simulator, the background image does not appear. It starts white then goes to black after the first rotation. I’ve checked and rechecked my inspector panes look exactly as above but still not working. Initially, I failed to “copy to project” but I went back and removed that version of the png file, re-added it with copy, then rebuilt the interface (leaving the original label intact). It looks fine in the Interface Builder, just doesn’t appear in the simulator. Any suggestions as to what I have done wrong?

chano

Thank you Henry. More like this would be a real boon.
Or think about the same illustrative approach offered for a small instalment based fee.

Patrick Santana

I liked that you used the Interface Builder. A lot of developer don’t use even for things that would be very simple to do with it.

BTW, nice background. :-)

Henry Balanon

Thanks guys. Hey if there are any typos or things that need extra explaining, send me a note at theappleblog at balanon dot com

jorje

hi, i was wondering what project format this is (orientation based,view based etc.)
thanks for any help

Patrick Santana

It is nice to see that The Apple Blog will also join for development articles.

It is a good article. Looking forward next one!

Thomas Constant

Thanks for a nice, readable, and easy to follow tutorial. Not enough of these floating around so hope to see more of them from you.

Comments are closed.