Advanced layouts and animations are essential to your app's interface. Gain insights into group layout mechanics and the new element animation APIs introduced in WatchKit for watchOS 2. Understand how to create layouts that work well with animations and learn other techniques to add liveliness to your apps.
MIGUEL SANCHEZ: Hello, everyone.
Welcome session 216, Layout
and Animation Techniques for WatchKit.
My name is Miguel Sanchez, I'm a WatchKit engineer.
Later you will hear from my colleague Tom Witkin.
So the agenda for today is to give you an overview
of the layout fundamentals of WatchKit.
I will be going into more detail about how to use groups to set
up your complex layouts, and then you will hear from Tom,
talking to you about animation techniques existing already
in Watch OS 1, as well as in the new APIs
that we are introducing in Watch OS 2.
So our target audience for this talk is the whole range
of WatchKit developers,
people that haven't seen the platform yet, and are learning
about the layout as well as --
as well as those of you who have already had experience with it.
So let's start with the layout fundamentals.
The WatchKit layout model,
I should say off the bat is the same layout model
that we have since WatchKit OS 1.
WatchKit and Watch OS q.
If you haven't used it yet, it's a different model from the UIKit
and the AppKit models that you may have had experiences with.
The difference is that in WatchKit we are using a flow
based layout and what I mean by that is,
you've probably seen this animation before,
in Interface Builder, you have your library of,
and your catalog of WatchKit objects
and you are dragging them on to your controller.
As you are dragging them, they are falling
on the next available slot on the flow.
And that flow is initially vertical.
So here you have a second element.
It falls on its set slot, and, of course,
you can add a horizontal flow if you introduce a grouping object
and tell it to use horizontal layout.
So some important points as a programmer
of WatchKit applications is
that you are not writing object creation code.
All of your UI creation is happening in story boards
and Interface Builder.
We are not providing APIsor allocating your typical
This does not mean that you don't have fine-tune control
of your layout hierarchies and alignment and sizing,
as well as animation, as you will see here.
So we'll go into each one of these in detail.
Let's start out with alignment and sizing.
All of your instances
of WatchKit objects are subclasses of WKInterfaceObject.
All of these have properties for setting the alignment,
and the sizing heuristics.
So alignment, we are referring
to the alignment inside the containing object.
This is the horizontal and the vertical alignment
and it can either be left, center or right.
For sizing, you are telling us what rules you want us to use
when sizing your objects both width-wise and height-wise
and this is either fixed, relative or sized to fit.
In Watch OS 2, these -- these properties have been available
in Interface Builder since Watch OS 1, but in Watch OS 2,
we are exposing more of these through APIs.
We want to give you more control in your code but also
to animate them as you'll see later.
This is a new API set horizontal
and vertical alignment with new enum types.
This does what you expect.
Here you have the world premier
of WK blue box doing a left top alignment, center,
center, and right bottom.
On the sizing API side,
we already had said width and said height.
For washWatch OS 2, we are exposing the relative width
and the sizing to fit APIs.
Again, it gives you more control in your code.
Graphically this looks like the following:
so here's a fixed width and height
of our blue square, once again.
If you have been using this in the previous release,
you should know that we interpret the value
of zero differently.
In Watch OS 1, if you give us a zero in code, we revert it
to the storyboard value, in Watch OS 2,
we are interpreting the zero as an absolute zero value.
So just keep that in mind.
Let's say that you want to size the rectangle to be 75%
of the width of the containing element.
So you can use said relative width, with a .75 value
and you get three-fourths of the width.
And you can do the same for the height, if you want it
to be half of the height of your containing element.
The second parameter in these APIs is an adjustment value,
which can be positive or negative, and it's applied
after you do the initial sizing.
So in this case, I will be adding 30 to the width
and subtracting 30 to the height and I get the following.
And finally, the sizing to fit and sizing
to height does what you probably expect.
You know, depending on the content inside your rectangle,
we are sizing appropriately.
Now, let's move on to group elements.
This is where you really start to fine tune your layout.
WKInterfaceGroup, think of it initially as a container
without default content.
It can have content as I will illustrate later
but initially it's just a container.
It's a tool for arranging all of your elements.
This is where you get the chance
to pick whether you want a vertical or horizontal layout.
This is also where you start to introduce nesting.
And this is where you are tweaking the alignment
and the sizing that we just saw before
on the containing elements.
So as we saw in the first set of slides, now I'm abstracting
to the blue shapes, you are laying your interface
in Interface Builder and you have the vertical layout.
You introduce a group and you tell it in Interface Builder
that you want the horizontal layout and you start laying
out your objects there.
So once you have defined your containment hierarchy,
you are able to define things like insets
and spacings within your group.
So you can define the left inset here.
These are point values.
Left inset, bottom inset, top inset, right inset and right,
as well as the spacing that is used to put aside --
to separate each one of your elements.
Now, don't forget that your top level container object is also
-- is also a group.
So you can set the insets at that level,
as well as the spacing.
So we use the same spacing for the number of elements
that you have inside of your group.
So here you have a spacing of 10 that is used
for the three top level elements in your group.
Now, once you apply -- once you start using nesting,
you are able to achieve your complex layouts.
Here's a very simple example.
If you want the two squares stacked on top of each other,
followed by two squares right next to each other,
you first use a group with a vertical layout.
Then you use another group with a horizontal layout
and you wrap those two in another group
because that's the way you achieve the horizontal layout
of those two elements.
And by default, there's no content in your groups.
So they are transparent and you only see your squares.
Now, let's make this more concrete with an example
that I will be introducing in this part of the session
and then Tom will start animating.
So we have WKRecipes.
This is a very simple recipe viewer.
It lists your recipes.
Fish tacos, pizza, barbecue wings.
You can see the list of ingredients for each one
of your recipes, and you can see the number of servings
for each one of the recipes.
And there are other screens which Tom will talk
about in the context of animation.
For here, we are focusing on the static layout
of these three elements.
So how do we do this?
The first screen that we see is a table of recipes.
So in WatchKit, you have a table controller that you can use
to layout your rows, but it's your responsibility
to tell us what each row looks like.
What is the structure of that?
So here we want an image and a label.
So we have a horizontal layout,
that should automatically tell you that that's a group
with a horizontal layout.
Then you have defined your containment hierarchy,
and now you are going to define your spacings.
So you have your left inset,
your bottom, top, and the spacing.
And your alignment.
Right? Your image is aligned center, vertically,
but it's aligned to the left in the next slot that it falls on.
And the label also has a vertical alignment
but left aligned.
Notice that it's left aligned in the slot that it corresponds to,
right, because there's an image before it, so right next to it.
Sizing our images are square.
So we have a fixed size of 30 points on each side.
And the label, obviously sizes to fit.
So table row layouts show us that we can use the groups
for horizontal sizing, and then we can fine tune our alignments,
and set some spacing.
Now, let's move on to the ingredients controller.
Some of you might be noticing that five hot sauce,
whatever units that is, is probably too much hot sauce
for any taco recipe, but that's the wrong thing to focus on.
You actually want to notice
that although we have our table layout, we have rows,
we now have the circle element.
How do we achieve this?
The horizontal layout is the same.
We still have a group.
We have the label, obviously,
but what is that red circle on the top left?
We can nest groups, as I said before.
So we are using a group here.
And here we are now moving into the area
where groups do have backgrounds.
They don't have default content, but they can have backgrounds.
The backgrounds can be either colors or images.
So we can select the image of this group,
as well as the radius that is used to draw the background.
And so we are setting a group with a colored background,
blue in the schematic, red in the real example with a radius
of 8 and then you get the nice blue circle.
Once you have a group, you can nest the label inside it
and it's centered in the group.
Now you have the horizontal and the vertical centering
so this is where you start to see the building of concepts
that we have been talking about.
And yet again, sorry to be repetitive,
but this is the model.
Now you define -- you find tune your left inset,
top, bottom, and spacing.
So remember, for nested groups, you can use nesting
to achieve complex layouts, as well as using backgrounds
within your groups whether that's a color, or an image.
Lastly, we have the servings controller,
which it highlights the number --
it's a circle that highlights the number of servings,
four in this example, for your particular recipe.
So some of you might be thinking,
this is a circular layout.
How does this -- how is this achieved
in the grid-like flow layout
that you have been talking about so far?
So we have a circle of 12 --
well, a circular pattern of 12 objects, but if we look at them
in detail, these are actually just three top level groups.
So we have the first group,
the second group, and the third group.
Inside of those groups, we subsequently use more nesting.
So let's focus on the middle group.
Sorry, let me talk about the --
at the top level groups we do have alignment of the groups.
For example, the top group is horizontally aligned
in the center and fixed size.
The middle one is sized to fit --
to take up the whole width of the container.
So now the second group has more groups inside of it, right?
So we have a group with vertical layout.
Then we have a group with horizontal layout
and finally we have a third group with horizontal --
with another vertical layout.
And if we look at each one of those,
those themselves are made up of more subgroups.
Once we have this level of definition,
we can indicate the alignment, the precise alignment
on each one of those circles.
Now you can clearly see
that that circle is horizontally aligned to the right
and vertically on the top.
Then you have the left alignment and the center
for this particular circle.
And right bottom for the other, right?
So you have seen how the grid-like flow layout really
gives you a lot of power in terms
of the things you can achieve and that's the same pattern
that we follow for the whole -- for the whole circle here.
So group nesting is your key to achieving complex layouts.
Now that I have given you all of this rope, I need to warn you,
don't hang yourself with it.
It is possible to abuse groups, right?
You have to keep that in mind.
You can go overboard by trying to nest everything.
So some things to keep in mind.
I can't give you an exact number.
It depends on what your backgrounds are
or how your layout is behaving, but keep these things in mind.
At the beginning of the presentation,
I said that we are not offering you APIs
for direct element creation, or destruction.
This is all done in the storyboards
and Interface Builder.
So anything you create
in Interface Builder is instantiated.
When you're instantiating one of your controllers,
you're instantiating all of the elements inside of it.
It's possible to hide some of them.
That's one of the properties that you have for some
of the elements, but even though they are hidden,
you are still -- we are still creating them.
So you might -- you are still taking the hit
of the creation costs.
You might save on the layout costs
because we are not doing the layout,
but the creation is still happening.
So keep this in mind as you start adding a bunch of objects
into your controllers, right?
Keep them -- in mind that those are all being created even
if they are not visible at that particular time.
And finally, as I showed you with groups and their ability
to have images, keep in mind that images have a transfer cost
over into your Apple Watch.
In Watch OS 1 apps, the extension was running
on the phone, and they have to get --
we have to get those images over into your watch, right?
Each time your user is using your interface.
So keep that in mind.
We have APIs for image caching which we kind of --
you tell us to move a certain set of images
but they still have to get over the air to your watch.
In Watch OS 2, this is less relevant
because the extension is running on your watch,
but you still have to install the app.
So you still have a set of resources
that you are installing.
So there is still a transfer cost for your users
from an installation point of view.
So always remember
to use appropriate sizes for your images.
If you give us an image, we will resize it
for whatever you tell us to display on the screen.
But by doing, that you are adding more processing cycles
from our -- from the WatchKit side on the watch, right?
So you have the ability to resize your images properly,
either on the phone or in your servers, if they happen
to be dynamic images and this makes an impact,
in terms of the rendering of your UI.
Finally, you will have some images that need
to be resized, for example, buttons.
You can use -- you don't need multiple sizes.
You can use image slicing.
This is a UI that you have in your asset catalogs
and Interface Builder, you can slice your images
and tell us how they are resizing
and we do the right thing.
So you can give us one particular image set
and we will -- it will be applicable
for different sizes in your UI.
So this is the end of the static part of the talk and now I would
like to invite Tom up to add more dynamic aspects
to this model.
TOM WITKIN: Awesome.
Hello. I'm Tom, I also work on WatchKit.
We will be discussing animations and introducing those
into both your existing and your new Watch OS 2 apps.
We will start off with some existing types
of animation available in Watch OS 1.
So tables are really flexible.
In certain updates on tables will already animate.
If you insert rows, if you remove rows
or if you update the content within a row,
they will actually animate and we will talk about all of these.
So all of our examples are going to be
within the context of our recipe app.
So let's start on the recipe list.
And it would be great if we could provide a way
to sort the list, either -- so by ranking that we have assigned
or maybe alphabetical.
It's not extremely clear how the list is being sorted
as we are doing this.
And so it would be great if we could possibly insert a row
and say how the list is sorted and then after a couple
of seconds, take it out of the UI.
So how are we doing this?
It's really simple.
We have a table.
And we are calling insert rows and indexes
and we are inserting a row of status type.
And then we are getting the row controller and updating the text
on that row and then we are scheduling a timer
for a few seconds to remove the row
and that method is then implemented here.
And so inserting and removing rows can really add flexibility
into your interfaces.
And one thing to point out is you can insert
or remove rows of any type.
So for example, here we have a list of recipes,
all the same type of cell, however we are inserting a row
of an entirely different type.
So, again, it allows you to have extremely dynamic content.
So within your interfaces.
I will also point out that if you want to update your tables
and not animate we have 2 API that I'm sure you all know
if you've used WatchKit or Watch OS 1.
So moving on to the content within a row and we will tap
into our detailed view of our recipe.
And we have a description.
And because of the size of Apple Watch, and the length
of a description, we probably don't want
to have the full description there all the time.
And so we have implemented our description within a table row
and we show a truncated version.
It would be great if you tap on the row, it will expand in place
and give the full description.
And so it's really nice -- it's a nice animation and it --
it provides you -- and so the information you want,
exactly when you want it.
So how are we achieving this?
I will go back to our blue boxes.
So we have our table cell.
And within the cell, we have a few labels.
So we have our short label, which has a description
with the truncated text.
We have another label, which says tap to show more.
And then also we actually have a third label.
So that's a full descriptionlabel.
So the initial state of our cell has the full description label
hidden and all we are doing is the user taps on the cell,
is we are reversing this.
So we will unhide the full description label
and we will hide the other ones and just this will allow
that animation to happen, that we handle in WatchKit.
So it's really simple.
And, again, here's the code.
So just in a few lines of code -- within your application,
and it's a really great experience.
And so, again, rows reload,
whenever their content changes in height.
So if you are reloading a row but it doesn't change
in height, there's no animation.
And so in order to achieve this, make sure your rows have a size
to fit height, because if they have a fixed height,
again the row isn't actually changing.
So now we will go back to our recipe list
and visit a different type of animation.
And back to our cell and I will call out these arrows here.
It would be great if, as its displayed,
we could add a flourish of some type
so the arrows spin around, for example.
We can accomplish this with an animated image.
So animated images are really powerful, and they allow you
to cycle through a series of images over a given duration.
And they also allow you to repeat and reverse animations.
And it's the only type of animation
within WatchKit that will allow that.
So, again, there are very powerful.
I do want to point out, though, if you do have a series
of images -- so the number of images can quickly add up
and so their costs in terms of load times and performance,
as well as -- and so memory usage.
Keep that in mind and reduce the number of images as far
as you can, and the size of the -- and the size of the images
and you will get better performance.
I also want to point out now our new picker object,
in Watch OS 2, and it allows you to scrub through the images
within an animated image so with a Digital Crown.
It's really powerful and it's a great experience.
If you would like more information, there is a session,
it's WatchKit In-Depth Part 2, it's to learn
about the new picker object.
So that's existing functionality in WatchKit.
I know a lot of people are interested in the new stuff,
and so the animation API that we are introducing in Watch OS 2.
So the animation API allows to you animate certain properties
on your interface objects, including the opacity, the width
and the height, the alignment, so left to right
or top and bottom or center.
The background colors on groups, so the color or the tint
on an image like we have here on the slide and the group insets.
So a lot of stuff that you can animate.
If you have used -- if you have programmed on iOS,
the API may look familiar.
It takes a duration and an animation block
and all the updates you perform
within the animation block will be animated
to the given duration.
So we will just jump right in and talk about some examples
and hopefully show some techniques,
as well as how you can integrate this into your WatchKit apps.
And so our first example will go back to our detailed view
in the app and tap into the serving screen.
And we are going to add an animation of where the circles
around the ring will fade in sequentially.
So like this.
So in code, we are going to loop through our groups
around that outer ring.
So every circle is a group.
We will create a dispatch block and schedule our animation.
And then within the block, we will animate the alpha
of the group, and it will fade in.
So it's a very simple, but you get a cool effect.
I also want to point out, we are introducing two new API.
So did appear and will disappear and they are
These are important for your animation and I will talk
about that in a moment, I'll also point
out that this is coming in a future seed.
So in this interface, use did appear not will activate
if you are beginning an animation
on the appearance of a view.
I know a lot of people are using will activate right now
to start an animation, so will activate is probably called
prior to it appearing on the screen so it's not a good place
to start your animation.
So use the did appear method.
Also you can stagger your animations with timers or GCD.
If you do this, keep in mind,
that you can only update a controller if it's active and so
if you are animating after the controller has deactivated.
So those updates won't actually be applied and so keep
that in mind and make sure your controller is active.
Also keep track of the total duration of your animation.
If you are chaining a lot of animations,
the duration can quickly add up,
and most likely the user is only interacting with your app
for a few seconds and if you have a multisecond animation,
it's just prolonging your times within your apps.
So be mindful of that.
And also just for convenience, you can set your initial values
within the storyboard.
So for example, in this interface, all of the --
so all the circles are initially hidden and have an alpha zero
at the start and we can have that in the storyboard
and not have to worry about it at runtime.
So we will move on to our second example,
which is our ingredients screen.
And it would be nice if we could have the labels fly in.
So as you can see here.
So we'll break out to our blue boxes.
And so we have our table row.
And as we showed earlier, we have our number background
on the left which is the group
and we have our label on the right.
And now we are going to add a new group in between the two
and we will call it a spacer group.
And groups are really powerful in terms of laying
out the content within them
but they can also affect the content around them.
So because the content --
and so because our layout in WatchKit is flow based,
a group within the flow can affect the other ones.
So, for example, here, our initial state
of the cell has the spacer group to be a full width and what
that does is it actually pushes the label off the side
of the screen, and so you can use this within --
so within your apps, both for horizontal flow
and vertical flow to kind of affect
where things are laying out.
And then as we animate, all we are doing is updating the width
of our spacer group and that label then will come in,
because we are recalculating how our flow is laying
out the interface.
So in code, we are looping through all of our table rows
and we are fading in both our number background and label,
as well as setting the width on that spacer group
and we are wrapping all of this
within in a single animation block.
If you can, you can improve your performance by wrapping all
of your animations within a single block, however,
as I just -- as I showed,
if you are doing a sequential animation that's fine,
but just keep in mind that having a lot of animations
at once can affect the performance.
So invisible spacer groups are really powerful
and you can adjust the width, height or alignment of them
and affect your layout.
And one thing to point out is as you animate, we actually relay
out your entire interface and this is how I can set the width
on that group and the label is actually changing its position,
even though I'm not -- and so I'm not changing it myself.
And so now on to our third example,
which is the most complex of the examples.
So we have this screen where you can add a note, and we'll --
and if you tap on add note, we will have our default
on text input on the system.
If you choose an option, we'll insert --
or we'll animate in a speech bubble.
And so already we have a more complex animation
but we're going to go one step further on this.
And if you tap confirm, we will animate
in a confirmation screen.
So all of this is within one interface
and it's all using the new animation API.
And so we will break this up into two parts.
Let's talk about the speech bubble first.
So back to a wire frame.
Within our interface, we have a group
and that's the text container I will call it.
Within that, we have our text bubble which is on top,
which has our label in it.
And then below that, we have our confirmation button.
As we animate, our initial state has our text, so bottom
and right aligned, as you can see here,
the button is faded out.
As we animate, we will update the width of our text bubble
and the height and fade both that
and the button in, as you can see here.
And so we get that effect --
and so we get that effect with just a few lines of code.
On the text bubble, we were updating the width,
the height and alpha as I said.
And the size to fit height is because we want
to fit the full text of that label.
Regardless of how long that note is, it will fit.
We will fade in the button by updating the alpha
and we'll update the height of the text container
as well to fit everything.
And wrapping all of that within an animation block.
So that's part one of that animation.
Part two is where we show the confirmation screen.
And so back to our blue boxes.
Here we have our text container and I won't include the objects
within that here just for clarity.
But also within the interface below, we have another group,
which I will call the confirmation container.
And so what we are doing here is we are wrapping the different
parts of our interfaces in their own groups,
and what that allows us is we can --
we can collapse or expand them
to show different parts of the interface.
For example, here is the initial state of that interface.
So the text container is full height
and the confirmation container actually has a height of zero
and so it's hidden on screen.
And because of how our new behavior in the set width
and set height API, you can actually achieve a higher width
As we animate, all we're doing is reversing the heights
So the text container now has a height of zero
and the confirmation container now is a full height
of the screen.
In code, it's exactly what I said, we are updating the height
of the text container,
the height of the confirmation container and just wrapping
that within an animation block.
And so that's how you get the effect of one part
of the interface sort of zooming off screen
and the other zooming on.
And so I want to bring out a few notes on animation, just to kind
of wrap up and summarize but also just to point
out a few gotchas that you might run into.
So any update that affects the sizing
of your interface objects can actually --
can actually animate the layout.
So, for example, if you update the text of a label,
that is sized to fit, that label is changing in width or height
and so if you do that within an animation block,
it will actually animate to the new frame of that label.
However, you won't actually be animating the application
of the text, but just the sizing of that label.
If you have lots of animations at once
or if you have a complex type of layout within your interface,
that can affect the performance, and so definitely keep
that in mind, and absolutely make sure to test on hardware.
So the simulator is a great way to build up your animations
and to make sure everything is working,
but for actual performance
and to see how things will actually work,
make sure to test on hardware.
That's extremely important.
And also a thing to point out is
that this animation is functional
within your applications.
However, if you call it within a glance or notification.
So those updates will still be applied
but they won't be animated.
And so there's no point in using this
within a glance or a notification.
A few more notes.
So use with restraint.
And that's because animation,
it should never be the focus of your interface.
If the animation is the reason that your interface exists,
it probably is time to rethink that.
And also, again, keep the total duration short.
We -- so the amount of time within your app is probably
on the order of seconds and so don't prolong the animation,
like, any more than you have to.
And there's a great session on this,
"Designing with Animation", I highly recommend that.
And so to wrap up and conclude the talk, and so layout
in WatchKit is different than UIKit and AppKitt
where it's specified in design time
but very flexible at runtime.
We have a lot of API and we're introducing a lot of new API
that allows you to update, to update your UI at one time.
Again, it's flow based
and so you are specifying the layout heuristics
of your objects but WatchKit itself is doing all the layout.
And groups are really powerful.
And as you have seen, you can build very complex interfaces
that you may not have thought were possible within WatchKit.
And now to add animation within your apps.
So animation is a great way to add liveliness or feedback
within your apps, I'm sure you all know that.
We have lots of ways already within WatchKit
that you can introduce these animations and we are making
that even more powerful in Watch OS 2.
So for more information, there's a lot of documentation
and technical support, we will also be releasing our sample
code as a project on developer.Apple.com.
And for general questions we have our evangelist,
So ask him all the questions you may have.
There's tons of related content this week
and some are still happening.
I want to point out the Tips and Tricks one tomorrow morning,
and the Design Tips and Tricks one tomorrow afternoon.
So both are very good.
So thank you.
Enjoy your time here.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.