Tag Archives: Apple Watch

How to draw a triangle in Apple Watch

I’ve previously covered how to draw circles and rectangles into an image when writing an Apple Watch app. I had an idea for another watch face that needed triangles – these need a different approach using Watch Kit. Basically, you have to draw a path around the perimeter of the triangle (or any other shape), then fill in the shape. Here’s a function to draw a triangle that points to the left:

    internal func drawTriangle( _ context : CGContext?, centreX : CGFloat, centreY : CGFloat, size : CGFloat, colour : CGColor )
        context?.move(to: CGPoint(x: centreX - size/2.0, y: centreY))
        context?.addLine(to: CGPoint(x: centreX + size/2.0, y: centreY - size/2.0))
        context?.addLine(to: CGPoint(x: centreX + size/2.0, y: centreY + size/2.0))

And this is the code for drawing a rectangle:

    internal func drawRectangle( _ context : CGContext?, centreX : CGFloat, centreY : CGFloat, width : CGFloat, height : CGFloat, colour : CGColor )
        let origin = CGPoint( x: centreX - width/2.0, y : centreY - height/2.0 )
        let rect = CGRect( origin : origin, size : CGSize(width: width, height: height) )

Once you can do those primitive triangle/rectangle operations, you can put them together to render any digit you like. So I used them to draw a ‘timeometer’ in this speedo watch face:

The dial is rendered as a series of ticks – at the moment, it shows minutes and hours. I have to admit I still tend to read the time from the digits at the bottom, so I may change the dial to show seconds and minutes instead.

Leave a comment

Filed under Programming, Swift

How to use the Digital Crown in a Watch Face App

I’ve written before that, having lived with the Apple Watch for a while, I felt the watch faces lacked variety. So, I wrote a watch face app, which I now use for the majority of the time.

For my next watch face, I thought it would be pretty cool to recreate the look of my beloved Tissot watch. One of its best features is that extra functionality is controlled by twisting/pressing the bezel. It supports date/time/stopwatch/timer – or you can hide the digital display altogether. Although WatchKit doesn’t allow you to capture a button press, you can use the digital crown to scroll between choices – so I thought I’d offer a couple of date formats as well as the option to hide the date altogether. tissot

Add a Picker control onto your storyboard and connect it to a WKInterfacePicker in your InterfaceController. There are a number of styles that you can choose, but for my purposes, I chose the default List style:
Then it’s a matter of populating the picker’s list of items – for example, this code could go in function awake(withContext):

            let blankLine = WKPickerItem()
            blankLine.title = ""
            let currentDate = Date()
            let dayDateMonthLine = WKPickerItem()
            dayDateMonthLine.title = "\(currentDate.dayOfWeek()) \(currentDate.dayOfMonth()) \(currentDate.monthAsString())"
            let dateMonthYearLine = WKPickerItem()
            dateMonthYearLine.title = "\(currentDate.dayOfMonth()) \(currentDate.monthAsString()) \(currentDate.year())"
            InfoPicker.setHidden( false )
            InfoPicker.setItems( [ blankLine, dayDateMonthLine, dateMonthYearLine, blankLine ] )

I set the focus on the picker so that the digital crown is immediately responsive (otherwise, you’d have to select the picker first on the touch screen). I also put a blank line before and after the date formats, to make the usage more natural. The code above also uses some extension methods on Date.

Tissot style watch face

Seeing how good this looks, I think Apple are missing a trick. All of their analogue Apple Watch faces are round – I hope they ship a couple of rectangular faces in the next Watch OS upgrade.


Filed under Programming, Swift

How to write a Watch Face App for Apple Watch

Having owned an Apple Watch for over a year, I’ve grown a little bored with the available watch faces. So I was very impressed with the new, special edition Hermes watch face. This is quite different to any of the other faces on the Apple Watch. Unfortunately, it’s only available to new purchasers who buy the brand new Hermes Apple Watch – starting at £1000.

Having written my first Watch App recently, I thought I’d have a go at writing a Watch Face App. Apple WatchKit doesn’t officially support writing watch faces, so this would have to be an ordinary App that happens to display the time. There are plenty of custom faces you can use as wall-paper to create an attractive digital watch, but I wanted the analogue look.

The approach I took was:

  • Start with an image e.g. from the custom faces library
  • Look up how to get the current time in the WatchKit API
  • Find out how to draw graphics on top of an image
  • Work out the maths to draw the hands in the right place
  • Work out how to render proper watch hands

I already blogged about how to get the current time and how to draw graphics on top of an image. So if you followed along, you can replace your Treasure Map image with a watch face image and use the createContext(), drawLine() and applyContextToImage() methods to draw the hour and minute hands. In fact, by making the colour a parameter of drawLine(), you’ve got the method to draw the second hand too.

As for the maths to draw the hands in the right place, it’s trigonometry. Both sin and cos are available in WatchKit, so convert the hours/minutes into radians and calculate the end coordinate of your watch hand, treating the length of the hand as the hypotenuse of a right-angled triangle.

[edit]I had a request to post the maths for this. Suppose you want to draw a hand at 12 minutes past. Convert that into a fraction of how far the hand has moved – here, 12 mins out of a possible 60 mins. Then work out whether it’s in the top-right, bottom-right, bottom-left or top-left quadrant of the watch face (that affects which sin/cos functions you’ll use) – here, 12/60 = 0.2, so it’s between 0.0 and 0.25, hence it’s in the first quadrant.

To calculate the x and y coordinates for the top-right quadrant, we form a right-angled triangle between the hand and the y-axis. The hand forms the hypotenuse of the triangle, let’s choose length = 100. So knowing the minutes as a fraction, and the length of the hand, here’s a function to calculate the x and y coordinates as an offset from the centre of the watch face, using trigonometry:

func handCoordinate( _ fraction : CGFloat, length : CGFloat ) -> (x : CGFloat, y : CGFloat )
let x : CGFloat, y : CGFloat

if ( 0 <= fraction && fraction < 0.25 )
let theta = CGFloat( (fraction/0.25) * π / 2.0 )
x = length * sin( theta )
y = -1.0 * length * cos( theta )
// remaining quadrants left as exercise for the reader!

return (x,y)

The simplest way of drawing the hand is then a simple drawLine() from (centreX, centreY) to (centreX + x, centreY + y). For my 42mm watch, centreX and centreY are (156,150) – other sizes will vary.

That leaves the trick of how to draw a proper watch hand given only the drawLine() and drawCircle() methods. This is the method I used:


In order to draw the white circle outline with solid black inner-circle, I used this method:

    func drawCircle( context : CGContext?, radius : CGFloat, centreX : CGFloat, centreY : CGFloat, colour : CGColor )
        let diameter = radius * 2.0
        let rect = CGRect( x: centreX - radius, y : centreY - radius, width : diameter, height : diameter )
        CGContextSetFillColorWithColor( context, UIColor.blackColor().CGColor )
        CGContextFillEllipseInRect( context, rect )
        CGContextSetLineWidth( context, 2.0 )
        CGContextSetStrokeColorWithColor( context, colour )
        CGContextStrokeEllipseInRect( context, rect )

There are a couple of limitations:

That said, I’m really happy with the results:

Watch Face App

This is actually one Watch App – I changed the Image to a Button so that I could iterate through different watch faces by tapping the watch. If you do this, call button.setBackgroundImage on the button instead of image.setImage.

See also: How to draw text onto an image and How to draw on top of an image.


Filed under Programming, Swift

How to draw on top of an image in Apple WatchKit

Suppose you’re writing a simple game for Apple Watch – for example, you might have a treasure map image and you want to render a cross on it in a random position to locate the treasure.
This is tricky, because WatchKit severely limits your options for laying out UI primitives on the screen. For example, if you put a label and an image onto a StoryBoard, it will tile them (rather than letting you put one on top of the other).

The approach I’ve adopted is:

  • Create a Group in the story board and set its background image
  • Add an image view within the Group
  • Create a context and use CoreGraphics to write into it
  • Apply the context to the image view

Set up a new iOS WatchKit App, then drag a Group and Image from the Object Library onto the storyboard:
TreasureMap StoryBoard

In the WatchKit App assets, create a new image set and drag your background image onto the x2 outline:
TreasureMap ImageSet

Set the background image on the group:
TreasureMap SetBackground

Then create an outlet in the InterfaceController for the image – one way is to control-drag from the outline view of the storyboard into the interface controller’s swift file. I called mine OverlayImage to convey the purpose.

Finally, add the code that will leverage the CoreGraphics library to draw into the overlay – the work is done in drawCross() which is called from awakeWithContext(). I’ve split out line and circle drawing methods for clarity.

class InterfaceController: WKInterfaceController {
    // Create by control-dragging to the StoryBoard
    @IBOutlet var OverlayImage: WKInterfaceImage!
    let imageWidth : CGFloat = 312.0
    let imageHeight : CGFloat = 348.0 // 390 - 42 for status bar on 42mm watch
    override func awakeWithContext(context: AnyObject?) {

    override func willActivate() { ... } // standard
    override func didDeactivate() { ... } // standard
    func drawCross()
        // Begin image context and grab context
        let context = createContext()
        // Draw our primitives
        drawLine( context, startX: 75, startY: 150, endX: 125, endY: 200 )
        drawLine( context, startX: 75, startY: 200, endX: 125, endY: 150 )
        drawCircle( context, radius : 10, centreX : 100, centreY : 175 )
        // End by applying our graphics to the Overlay image
        applyContextToImage( context )
    func createContext() -> CGContext?
        // The 'opaque' parameter is false, so that we overlay 
        // rather than the static image underneath
        UIGraphicsBeginImageContextWithOptions( CGSizeMake( imageWidth, imageHeight ), false, 0 )
        let context = UIGraphicsGetCurrentContext()
        CGContextBeginPath( context )
        return context
    func drawLine( context : CGContext?, startX : CGFloat, startY : CGFloat, endX : CGFloat, endY : CGFloat )
        CGContextSetStrokeColorWithColor( context, UIColor.blackColor().CGColor )
        CGContextSetLineWidth(context, 3.0)
        CGContextMoveToPoint( context, startX, startY )
        CGContextAddLineToPoint( context, endX, endY )
        CGContextStrokePath( context )
    func drawCircle( context : CGContext?, radius : CGFloat, centreX : CGFloat, centreY : CGFloat )
        let diameter = radius * 2.0
        let rect = CGRect( x: centreX - radius, y : centreY - radius, width : diameter, height : diameter )
        CGContextSetLineWidth( context, 3.0 )
        CGContextSetStrokeColorWithColor( context, UIColor.blackColor().CGColor )
        CGContextStrokeEllipseInRect( context, rect )
    func applyContextToImage( context : CGContext? )
        let img = UIGraphicsGetImageFromCurrentImageContext()
        OverlayImage.setImage( img )

All being well, you can now run your WatchKit App and check that the black cross and circle have been drawn on top of the background image!

TreasureMap WatchApp


Filed under Programming, Swift