Monday, April 18, 2016

Watch tutorial 3: Layout

This post is part of a set of short tutorials on Watch. If you want to see the previous post. In this tutorial, you're going to layout the screen needed to start the task from your Watch.

Are you a AutoLayout Guru?

Good. From Apple documentation:

Watch apps do not use the same layout model used by iOS apps. When assembling the scenes for your Watch app interface, Xcode arranges items for you, stacking them vertically on different lines. At runtime, Apple Watch takes those elements and lays them out based on the available space.

For Watch, you won't use AutoLayout!!!

AppleWatch Layout is much basic and therefore much easier to use :)

You must use storyboards to design your interfaces. Remember that storyboard is part of the WatchKit app bundle. Everything is laid down in storyboard, you won't be able to access a position coordinate at runtime. To me, Watch layout looks much more like box driven ie: CSS-like rather than constraints based Layout ie: iOS-like.

Get starter project

In case you missed Watch tutorial 2: Watch Architecture, here are the instructions how to get the starter project. Clone and get the initial project by running:
git clone https://github.com/corinnekrych/DoItCoach.git
cd DoItCoach
git checkout step2
open DoItCoach.xcodeproj

Laying out first screen


Add image resource

Download the Asset.assets folder from the final repo. In Finder copy paste Assets.xcassets folder into your project Watch App folder ie: /DoItCoach/DoItCoach WatchKit App/.

In DoItCoach WatchKit App in Project Navigator, select Assets.xcassets, should see the new images:


You're done with the images, let's go to DoItCoach WatchKit App's storyboard.

Start button layout

To be able to start the timer for a task,
  • Go to DoItCoach WatchKit App/Interface.storyboard
  • In the bottom right hand side Object Library search for a Group UI control.
  • Drag and drop the Group onto your main screen
  • In Attributes Inspector, choose Horizontal: Center, Vertical: Center, in Background select Time12 image, in Height select 0.9 to make sure the circle has no distortion.
  • In Object Library search for a Button UI control.
  • Drag and drop the Group onto your newly created group
  • In Attributes Inspector, select Content and assign the value Group.
  • In left hand side scene view, select the newly appeared Group below the Button, set its Height to Relative to Container
  • In Object Library search for a Image UI control.
  • In Attributes Inspector, select Image and assign the value Start. Choose Horizontal: Center, Vertical: Center.
  • In Object Library search for a Timer UI control.
  • Drag and drop the Timer onto your Button group. Oops! what is happening, you timer is out of screen. Remember, by default Group have a horizontal layout, go to the Group under your Button and change Layout to Vertical. You can now see your timer element. For your timer, choose Horizontal: Center, Vertical: Center, Hidden: true, Units: Second, Minute checked, Text Color: Green, Front: system, Ultra thin, 27.
Build and run.
Et voila!



Add outlets

To link UI controls to your Swift code, same technique as for iOS app: use outlet and actions.
  • Control drag Label to InterfaceController.swift, select outlet, name it taskNameLabel
  • Control drag Group (the top level one) to InterfaceController.swift, select outlet, name it group
  • Control drag Button to InterfaceController.swift, select outlet, name it startButton
  • Control drag Image underButton Group to InterfaceController.swift, select outlet, name it startButtonImage
  • Control drag Timer to InterfaceController.swift, select outlet, name it timer

Add Shared business model

To add Task business model to WatchKit App Extension, go to Build phases, in Compiled Sources, add Task.swift and TasksManager.swift.

In TasksManager.swift, replace the empty init() by the following one to bootstrap some values into your AppWatch:
public init() {
  self.tasks = [TaskActivity(name: "Task1", manager: self), TaskActivity(name: "Task", manager: self)]
}

App life cycle

In InterfaceController.swift, add display(task:) method as below:
func display(task: Task?) {
  guard let task = task else { // [1]
    taskNameLabel.setText("NOTHING TO DO :)")
    timer.setHidden(true)
    startButtonImage.setHidden(true)
    return
  }
  taskNameLabel.setText(task.name) // [2]
}
  • [1]: if there are no task available display in the task label: nothing to do and hide all other components
  • [2]: otherwise for a new task, display the task's name
In InterfaceController.swift, in awakeWithContext(context:) add a call to display method as below:
override func awakeWithContext(context: AnyObject?) {
  super.awakeWithContext(context)
  display(TasksManager.instance.currentTask)
}

Add action to Start

In InterfaceController.swift, in awakeWithContext(context:) add a call to display method as below:
@IBAction func onStartButton() {
  guard let currentTask = TasksManager.instance.currentTask else {return} // [1]
  if !currentTask.isStarted() { // [2]
    let duration = NSDate(timeIntervalSinceNow: currentTask.duration)
    timer.setDate(duration)
    timer.start() // [3]
    currentTask.start()
    startButtonImage.setHidden(true) // [4]
    timer.setHidden(false) // [5]
    taskNameLabel.setText(currentTask.name)
  }
}
  • [1]: if there are no task return
  • [2]: otherwise if the task is not already started
  • [3]: start it
  • [4]: hide start button
  • [5]: show timer

Get final project

If you want to check the final project, here are the instructions how to get it.
cd DoItCoach
git checkout step3
open DoItCoach.xcodeproj

What's next?

With this tutorial, you saw how you can layout your first AppleWatch screen, how you connect your UI element to the code to add dynamic effect on your screen. Now it is time to talk about animation: how do you make the ring show timer progress?

See Watch tutorial 4: Animation

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.