28 MarAnalog Clock using Quartz Core

Just want to share a simple example of using Quartz. I took a classic graphic task for – Analog Clock.

The drawing code is short and simple. It’s just necessary to undesrtand how measure angles of clock arrows from NSDatae and feel the difference between degrees and radians ;)

Inherite UIView and redefine “- (void)drawRect:(CGRect)rect ” method, which run when a UIView need to be displayed.
Mesure angles in readians from [NSDatae date] for Hour, Minute and Second.
Draw lines of clock arrows. A start point is the clock’s center. The end point is depends on measured angle.

inline double rad(double deg)
{
return deg / 180.0 * M_PI;
}

- (void) drawLineForContext:(const CGContextRef&)context Width:(float)_width angle:(double)_angle length:(double)radius
{
CGPoint c = CGPointMake(self.frame.size.width/2.0, self.frame.size.height/2.0);

CGContextSetLineWidth(context, _width);
CGContextMoveToPoint(context, self.center.x, self.center.y);
CGPoint addLines[] =
{
CGPointMake(self.frame.size.width/2.0, self.frame.size.height/2.0),
CGPointMake(radius*cos(_angle) +c.x, radius*sin(_angle) +c.y),
};

CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0]));
CGContextStrokePath(context);
}

- (void)drawRect:(CGRect)rect
{
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate* now = [NSDate date];
int h = [[cal components:NSHourCalendarUnit fromDate:now] hour];
int m = [[cal components:NSMinuteCalendarUnit fromDate:now] minute];
int s = [[cal components:NSSecondCalendarUnit fromDate:now] second];
[cal release];

BOOL isAM = hdouble hAlpha = rad((isAM?h:h-12)*30 +(30*m/60) -90);
double mAlpha = rad(m*6 -90);
double sAlpha = rad(s*6 -90);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
[self drawLineForContext:context Width:8.0 angle:hAlpha length:self.frame.size.width/2.0 - 18];
[self drawLineForContext:context Width:5.0 angle:mAlpha length:self.frame.size.width/2.0 - 12];
[self drawLineForContext:context Width:2.0 angle:sAlpha length:self.frame.size.width/2.0 - 10];
}
To finish the AnalogClock class it’s need start and stop methods:
-(void)update
{
[self setNeedsDisplay];
}

-(void)startClockUpdates
{
[self update];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(update) userInfo:nil repeats:YES];
}
-(void)stopClockUpdates
{
[timer invalidate], timer = nil;
}

To use the clocks you need to add our custom UIView to any UIViewController and call the start method.

#import “AnalogClockViewController.h”

@implementation AnalogClockViewController

- (void) viewWillAppear:(BOOL)animated
{
[clock startClockUpdates];
}

- (void) viewWillDisappear:(BOOL)animated
{
[clock stopClockUpdates];
}

- (void)dealloc {
[super dealloc];
}

@end

  • http://www.blogger.com/profile/17384788257194418250 Jackie

    Thanks so much for your brilliant work~~

  • http://www.blogger.com/profile/10136059479406321000 Slava

    You're welcome. How did you use it?

  • http://www.blogger.com/profile/01172329302460939915 Ironsienna

    This post has been removed by the author.

  • http://www.blogger.com/profile/01172329302460939915 Ironsienna

    Hello! Thanks so much for the example! However, I am using a different ViewController in my project and the clock does not work. I imported the AnalogClock.h and mm classes in my project and added #import “AnalogClock.h”
    in my viewcontroler.h and also IBOutlet AnalogClock* clock in the main body of the class; Then when I call the method [clock startClockUpdates] from my Viewcontroller.m nothing happens. I use multiple UIviews in my app and even when I tried to add [myview addSubview:clock]; before I call the StartClockUpdates method, nothing happened. Am I missing something? I am not using Interface builder at all in my app. Do I need to link something programatically??

    Thanks again though.. Your article is a huge source of info!!

  • http://www.blogger.com/profile/01172329302460939915 Ironsienna

    I also tried to do clock = [[AnalogClock alloc] init]; on top of my class.. No result.. Any help???

  • http://www.blogger.com/profile/01172329302460939915 Ironsienna

    Yay.. I found how to do it..

    Silly me.. I just needed to declare the clock like:

    clock= [[AnalogClock alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    clock.backgroundColor = [UIColor clearColor];

    Thanks again!!!

  • http://www.blogger.com/profile/10136059479406321000 Slava

    Hm.. sorry, I just didn't have notification about your comments. Sad.
    Does everything works properly?

    BTW, I just back to this code to integrate it to new customer project.
    have a nice day!

  • http://www.blogger.com/profile/17384788257194418250 Jackie

    I just saw your reply, sorry for replying late. I have been implementing an app which helps user better prepare LSAT. So i need this clock when user doing timed test. And i am trying to add graphics to it.

  • http://www.blogger.com/profile/07877874834939826343 Sean Naughton

    Hello, first thank you so much for the generous work. I am just starting to learn xcode and I have a demo project I am building.

    I am using the clock in a new ViewController. I can see the clock. It displays the correct time but I am unable to get it to update. How do I call the start method?

  • http://www.blogger.com/profile/07877874834939826343 Sean Naughton

    Ok.. forgive the NOOB posting but I did figure it out and the code works great ..

  • http://www.blogger.com/profile/18193015388610290147 Viajando nas NUVENS

    Hello Slava.
    Thank you for taking the time and the code!
    I'm using Xcode 3.2.4 64 bit with Xcode IDE 1708.0, 1705.0 Core Xcode, IB 3.2.4, 2.7 Instruments, Dashcode 3.0.2, Mac OS X 10.4 up to 10.6, 3.2 and iPhone OS 4.1 and iPhone Simulator 3.2 – 4.0 – 4.1.
    How could I adapt your code to work in the system above.
    Will be the first experience!
    Peace and prosperity!
    Silvio Pontes from Brazil.

  • http://www.blogger.com/profile/10136059479406321000 Slava

    Vlajando, I think you just need to update your project's settings, then the sample should be compiled properly.

  • http://www.blogger.com/profile/03256465812879435589 Sid

    I'm having a problem with the application. Drawrect is not invoked by setneedsdisplay. Any ideas as to what is wrong? I'm using Xcode 3.2.5.

    Thanks,
    Sid
    szzfrank@gmail.com

  • http://www.blogger.com/profile/10136059479406321000 Slava

    Download sources and run not changing code, it should work.
    To make it run with last iOS please change iOS version in project's settings.

  • http://www.blogger.com/profile/16497042634725396029 Andrew

    Thanks for making this tutorial, I learned a lot from it. Also, is there anyway to make the clock hands images, like in the real clock application that comes with an iPhone?

  • http://www.blogger.com/profile/10136059479406321000 Slava

    Andrew, you can replace custom drawing with UIImage drawing and customize this clock whatever you want.

  • http://www.blogger.com/profile/11661941597060177933 Gregir

    The app works when I compile your example code, but when I implement the code in my own project, I get the following error:

    “_rad” referenced from:
    -[ClockView drawRect:] in MyClock.o
    Symbol(s) not found

  • http://www.blogger.com/profile/10136059479406321000 Slava

    Admin, you should define radians “inline double rad(double deg)” in right place. It's easy, make a few more tries and clean&recompile.

  • http://www.blogger.com/profile/11661941597060177933 Gregir

    @Slava: (I changed my screenname from “Admin”. Not sure why it posted that way.) Makes total sense. It's my first time around with Xcode, so I'm still getting used to what error messages mean. Thanks very much for sharing your code.

    I defined radians in a new place and it worked fined. Thanks again.

  • http://www.imayaselvan.tk imayaselvan

    How to download the Source code?????

    Plz help

  • Seung-Un Ham

    How come there’s no project link?

    This code is too uncomfortable to copy and paste.

    • Slava

      Yes, moving from Blogger made a mass from this post. I’ll fix it soon.