57 Comments

Summary:

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 […]

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:


#import <UIKit/UIKit.h>

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

@end

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.


#import <UIKit/UIKit.h>

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

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

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


- (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]];

}

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:


// 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];
}

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;.


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

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.

You’re subscribed! If you like, you can update your settings

  1. Thomas Constant Wednesday, April 8, 2009

    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.

  2. Thank you so much. Especially pleased with your explanation of NSTimer.

  3. iphone Dev Sessions: How To Make An Orientation-Aware Clock – TheAppleBlog | iPhone App News Wednesday, April 8, 2009

    [...] Read More Tags: Basic Knowledge, Clock, Iphone, Orientation, Sdk, Sessions ← NIN iPhone app offers endless voyeurism to fans – Minneapolis City Pages [...]

  4. Patrick Santana Thursday, April 9, 2009

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

    It is a good article. Looking forward next one!

  5. MIDFR » Cours de développement Iphone Thursday, April 9, 2009

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

  6. How to make your iPhone application accelerometer / rotation aware ? | iPhone Development | iPhone Programming | iPhone Application Development | iPhone Game Development Thursday, April 9, 2009

    [...] very detailed iPhone Development tutorial in which author uses the example of a digital clock to describe how the app can handle the rotation [...]

  7. Henry Balanon Thursday, April 9, 2009

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

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

  8. Patrick Santana Thursday, April 9, 2009

    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. :-)

  9. 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.

  10. Jason Brownlee Thursday, April 9, 2009

    great tutorial mate. clear, not too verbose, just enough explanation.

Comments have been disabled for this post