Tag Archives: AppleWatch

How to draw text onto an image in Apple Watch App

Suppose you want to label an item in your WatchKit App. If you’re able to put a label widget onto the storyboard next to the item, that’s fine – but if you’re using Core Graphics to construct an overlay image, chances are you’ll need to draw the text onto the image too. My ultimate aim was to be able to draw the date on my Watch Face App.

It took some digging to find out how to do this. The obvious candidate was CoreGraphics.CGContextShowTextAtPoint, but that’s deprecated from WatchKit 2.0 onwards. Its replacement is the CoreText library, but “import CoreText” doesn’t find it.

CGContextShowTextAtPoint

Searching on StackOverflow met with little success, possibly because people’s solutions might work for iPhone Apps but don’t satisfy the restricted API available for WatchKit Apps. However, I found this gem which did work on the Apple Watch.

As a worked example, let’s take the Treasure Map App from an earlier post. It’s natural for a treasure map to indicate what’s buried at the cross. I’ve changed the method signature from the one on StackOverflow so that you specify the centre of the text block.

    func drawText( context : CGContext?, text : NSString, centreX : CGFloat, centreY : CGFloat )
    {
        let attributes = [
            NSFontAttributeName : UIFont.systemFontOfSize( 20 ),
            NSForegroundColorAttributeName : UIColor.blackColor()
        ]
        
        let textSize = text.sizeWithAttributes( attributes )
        
        text.drawInRect(
            CGRectMake( centreX - textSize.width / 2.0,
                        centreY - textSize.height / 2.0,
                        textSize.width,
                        textSize.height ),
            withAttributes : attributes )
    }    

Calling this from drawCross() in the Treasure Map App results in a neat label underneath the cross:

        drawText( context, text: "Gold", centreX: 100, centreY: 210 )

Screen Shot 2016-08-05 at 08.00.08

Using the same method, I updated my Watch Face App to draw the day and date onto this watch face:

Screen Shot 2016-08-07 at 21.28.23

See also: How to write a Watch Face App for Apple Watch and How to draw on top of an image in Apple WatchKit

1 Comment

Filed under Programming, Swift

Calculator App for Apple Watch

I was surprised that Apple didn’t include a calculator app with the Apple Watch. In the 1980’s, calculator watches were cool – having missed out then, I was keen for my Apple watch to have one.CasioCalculatorWatch

I chose to write my own calculator WatchKit App for fun, rather than purchasing one from the App Store. It’s a good choice for a first project, because the user interface is static and the focus is more on getting up the learning curve of WatchKit development. Here are some of the lessons I learnt in the process.

How to get the text from a WatchKit label
Suppose you’ve set up an outlet for a label that displays the input figures in your app – then you’d expect to be able to get the text back from it:

@IBOutlet var labelSum: WKInterfaceLabel!
//...
labelSum.setText( "42.0" )
let digits = labelSum.getText() // error - does not compile

It seems this is not supported in Xcode 7.2/Watch OS 2.1. Instead, you have to track the state in a variable and use that to populate the label.
How to store state in a WatchKit App
For a calculator App at least, you need a state machine to keep track of state, because at different stages you may be inputting the first or second number in the calculation, or re-using the previous answer in another calculation. Swift enum is a discriminated union that is well suited to this:

// Define enum type outside your interface controller
enum CalculationState
{
    case BuildingLHS( String )
    case BuildingRHS( LHS : String, Op : Operation, RHS : String ) // Waiting for Equals
    case WaitingForOperation( String ) // Got answer already, may do another operation
}

// Declare a variable to hold the state 
// as a member inside the interface controller class
class InterfaceController: WKInterfaceController {
    // ...
    var state : CalculationState
}

Use ‘RelativeToContainer’ to scale layout
When defining the UI elements on your story board, the interface controller is only approximately the size of the watch screen. My UI has all the buttons displayed at once, so it’s important to make maximum use of the screen size.
Calc - RelativeToContainer
Here, buttons 7, 8 and 9 are in a horizontal group. To fill that container, we need to use the ‘RelativeToContainer’ scaling style and fill in the proportion each UI element should take. For height, it’s 1 (i.e. the whole container), whereas for width, it’s one third (i.e. 0.33-ish). Personally, I think it would have been more obvious that this is the scaling style to choose if the proportion was displayed as a percentage, rather than a value relative to one.
How to set completion after animation
The WatchKit animation API lacks the ability to specify a completion function that runs after the initial animation changes. This is awkward if you want to flash a UI element from one colour and return to the original colour – if you run both animations in parallel, the colour doesn’t change. I used this code to add an extension method – then I could easily flash UI elements as below:

    func flashSum( origColor : UIColor, flashColor : UIColor ){
        animateWithDuration(0.25,
            animations: { () -> Void in self.labelSum.setTextColor( flashColor ) },
            completion: { () -> Void in self.labelSum.setTextColor( origColor )}
        )
    }

How to run WatchKit App on hardwareThis should be as simple as plugging the hardware into your MacBook (i.e. the iPhone that’s paired to the Apple Watch), selecting the correct device from the devices list, then running the App in the debugger. However, there are numerous pitfalls:

  • You need either a developer licence or a personal team set up. See Team | Identity in the Project settings
  • Xcode may think that the iPhone and Watch are unpaired – restarting Xcode solved this one for me, other people have had to re-boot their watch and/or phone
  • Xcode may not have the symbols for your Watch OS (this happened after I updated to Watch OS 2.1) – however, it seems happy to download them once you connect to the internet

Re-booting, re-connecting the phone to the MacBook, re-starting Xcode eventually sorted this out.
Conclusion
I’d already worked through a couple of tutorials for writing WatchKit apps, but you learn far more by writing your own.
Calc On Watch
The end result looks great, although the buttons are slightly too small for frequent use, even on a 42mm Apple Watch.

1 Comment

Filed under Programming, Swift

How to upload iOS App onto iPhone

XcodeI’ve been working on a hobby project for a while, learning Swift and gaining some experience of iOS App development. I reached the stage where the app was worth testing on my iPhone, but found that my version of Xcode (an early v7 beta) required an Apple Developer Licence!

Fortunately, it turns out that upgrading to Xcode 7.2 meant that I could upload to my own phone simply by providing my Apple ID. The upgrade was much easier than I had expected, compared to the number of bad reports on the internet. I used the App Store to upgrade, maybe it’s harder if you download and install the application directly.

Next, I had to find out how to install an application on my device from Xcode. First, connect the device to the Macbook and it will appear in the device list in Xcode above the simulated devices (i.e. all the iPhone and iPad models). Selecting the device by name and clicking run kicks off a full install and runs the app on the phone.

The final question was how to configure my phone to allow apps written by me to run – this was answered on the Apple Developer Forum, and is simply a matter of becoming familiar with Settings -> General -> Profile / Developer App.

I’m impressed by how well Xcode has automated this process, I’m sure a lot of work has gone into making installation onto a device a positive developer experience.

Leave a comment

Filed under Programming, Swift

Video: Animations

I was interested to see how animations are executed for Apple Watch apps.  These videos shed some light on it: WWDC 2015 Apple Developer Videos.  I watched:

  • Layout and animation techniques for WatchKit
  • Designing with Animation

It seems that a lot of the animations are ‘tricks’ achieved by tweaking the layout groups (either changing size, alignment or visibility).  Other recommendations include writing skeleton apps to mock animations by switching between images put together in KeyNote – this enables choosing between competing ideas without taking the time to code them all individually.

Leave a comment

Filed under Programming, Video

Video: Introducing WatchKit OS2

Catching up with this Intro to WatchKit OS2.  I found the following points interesting:

  • ClockKit has templates for watch kit complications, matching the different shapes and sizes available on the various watch faces
  • Complications should be immediately up to date when viewed, so watch kit allows you to bulk upload e.g. a timeline for a calendar widget that changes during the day.
  • Watch connectivity allows data sharing between phone and watch
  • CoreMotion, CoreLocation, MapKit and HealthKit APIs are available on the Watch

Leave a comment

Filed under Swift, Video