In part 1, we rebuild the elements in watch face with code, now it’s time to let them move.

Step 01: Setup the Minute hand and Second hand’s animation

In my concept, the Red Horizontal Line is moving like a hammer, the Half White Circle on the right hand side looks like a bell,the hammer will knock at the bell every minute. And the Horizontal Line’s moving will drive the Second hand’s rotation. So let’s setup Minute hand’s animation first.

redlineAnimation1 = new Animation
layer: RedLine
properties:
x: -40
curve: "ease"
time: 6
redlineAnimation2 = new Animation
layer: RedLine
properties:
x: -20
curve: "spring(400,20,0)"
time: 0.5

As you can see in the above code, I set two Animations for the Minute hand. The first one let it move left, it’s very slow, about 59 Seconds to help the Second hand rotate from Scale 0 to Scale 12 in real world. And the second one is moving back to right, the original position, it will take just quicker than 1 Second, to set back the rotation of the Second hand.

But in my case, I compress the duration in first animation, to about 6 Seconds, for easier to see the effect.

After typing these codes, you may still see nothing happen, because you should set the animation start with code like this:

redlineAnimation1.start()

But we don’t need them start right now, so after you confirm the effect, delete the “redlineAnimation1.start()”.

In Framer, you can set two animation loop pretty easy with just two lines of code, like this:

redlineAnimation1.on(Events.AnimationEnd, redlineAnimation2.start)
redlineAnimation2.on(Events.AnimationEnd, redlineAnimation1.start)

That means while Animation 1 comes an End, it will start Animation 2 automatically, and the same of Animation 2 for Animation 1.

It’s very similar in setting up the Second hand’s animation, codes like that:

secondAnimation1 = new Animation
layer: SecondLine
properties:
rotation: 72
time: 6

secondAnimation2 = new Animation
layer: SecondLine
properties:
rotation: -72
time: 0.5

Also, we will put these animations loop with the code:

secondAnimation1.on(Events.AnimationEnd, secondAnimation2.start)
secondAnimation2.on(Events.AnimationEnd, secondAnimation1.start)

Now we will move to the hardest part in this tutorial.

Step 02: Change the Number of Minute and Hour hand position.

We are going to write a function to change the time, so we code like this:

changeTime = ->

Change the time is easy, you just have to rotate the Hour hand and Minute Number. But before that, we still need some work to do.

First one is judge the rotation value of Hour hand. You may already know the Hour hand will rotate from -72 degree to 72 degree to perform the Hour changing. So each time it will rotate 12 degree, but the scales are not a circle, so at 12 0'clock it has to move back to -72 degree. As you remember we set statice values called “currentMinute” and “currentHourRotation” before, you should know we could used them to judge the condition like this:

if currentMinute == 59
if currentHourRotation == 72
currentHourRotation = -72
else
currentHourRotation = currentHourRotation + 12
HourWrap.animate
properties:
rotation: currentHourRotation
curve: "ease-out"
time: 0.5
delay: 0.3

So every time the Hour hand need to move, we check if it was sitting on the position of 12 o’clock, if yes, the currentHourRotation will equal to 72, and we set its position back by rotate it to -72 degree. If not, we just set an animation to rotate the Hour hand 12 degree each time, and update the currentHourRotation value.

You should also notice that a statice value called “currentMinuteIndex”, because I use a roulette like Layer with five children to help me change the Number of Minute, I need this statice value to mark which of the five is in the top.

The rotation of these five is clockwise, so every time the Minute change, the left side of the Top value should be the next Number going to show. And this one is who we should change its Layer.html value each time. So we also need a statice to hold that value, call it “nextMinuteIndex”.

But how? When we create these five Layers, they all have an index number, and that numbers won’t be changed. So we just need to compare the Layer.index to the “nextMinuteIndex”, and the code will looks like this:

if currentMinuteIndex == 5
nextMinuteIndex = 1
else
nextMinuteIndex = currentMinuteIndex + 1

# Set next Minute
if Layer.index == nextMinuteIndex
if currentMinute == 59
currentMinute = 0
else
currentMinute = currentMinute + 1
if currentMinute < 10
Layer.html = "0" + currentMinute
else
Layer.html = currentMinute

The last four lines of code are use for the style of Minute. It help me to set the single digits to something like “01” for consistency.

And we need to put the code above in a loop, we could use the Layer.children to find all the child of a Layer, and judge if one was belong to them. The code’s like this:

for Layer in MinutePoint.children

At the end of this loop function, we add the code to change the five Numbers’ rotation value.

Layer.animate
properties:
rotation: Layer.rotation + 72
time: 0.5
delay: 0.2

The last thing we should do in the Changing Time function is, update the value of “currentMinuteIndex”, because we have to set it back to 1 every 5 times. So the fully code of this function is:

changeTime = ->
# Change Hour with the Blue Ball
if currentMinute == 59
if currentHourRotation == 72
currentHourRotation = -72
else
currentHourRotation = currentHourRotation + 12
HourWrap.animate
properties:
rotation: currentHourRotation
curve: "ease-out"
time: 0.5
delay: 0.3

# Change Minutes
for Layer in MinutePoint.children
# Find the next Minute Label to change
if currentMinuteIndex == 5
nextMinuteIndex = 1
else
nextMinuteIndex = currentMinuteIndex + 1

# Set next Minute
if Layer.index == nextMinuteIndex
if currentMinute == 59
currentMinute = 0
else
currentMinute = currentMinute + 1
if currentMinute < 10
Layer.html = "0" + currentMinute
else
Layer.html = currentMinute

Layer.animate
properties:
rotation: Layer.rotation + 72
time: 0.5
delay: 0.2

if currentMinuteIndex == 5
currentMinuteIndex = 1
else
currentMinuteIndex = currentMinuteIndex + 1

Now if you type this two lines of code:

redlineAnimation1.start()
secondAnimation1.start()

You should see the watch face running perfectly. It’s nearly the End, except for one thing.

Step 03: the information dashboard

In my design, I just use half space of the screen to show the time, the other half, I want to use for some informations like “Steps”, “Calories” or “Weather”. The format is simple, and users can check them with a swipe interaction.

So in this example, we need to create a new PageComponent, it’s very easy to use in Framer to perform the page view swipe interaction. We still need two array to store the data, one for the value of the Informations, the other for the types of them. And we also need a new Layer to contain and clip the PageComponent, so the code is like:

dashboardDatas = ["1836", "130", "32℃", "76"]
dashboardLabels = ["Steps", "kCal", "GZ, Sunny", "Heart Rate"]
dashboardWrap = new Layer
width: 276
height: 276
parent: bg
midX: 160
midY: 160
borderRadius: 138
clip: true
backgroundColor: "rgba(0,0,0,0)"
dashboardPages = new PageComponent
width: 276
height: 140
parent: dashboardWrap
y: 160
scrollVertical: false

Then we just need to use a loop, to create four new Layer in the PageComponent, set their position from 0 to 276*4 (4 times of the width of their parent). And add two child to each Layer to show the Value and Type. That’s it, you should write the code like this:

for number in [0...4]
dashboardPage = new Layer
parent: dashboardPages.content
width: 276
height: 140
backgroundColor: "rgba(0,0,0,0)"
x: 276 * number
dashboardPageData = new Layer
width: 200
height: 48
parent: dashboardPage
midX: 138
y: 20
backgroundColor: "rgba(0,0,0,0)"
html: dashboardDatas[number]
color: "#efefef"
style:
"text-align" : "center"
"font-size" : "48px"
"font-weight" : "100"
dashboardPageType = new Layer
width: 160
height: 20
parent: dashboardPage
midX: 138
y: 56
backgroundColor: "rgba(0,0,0,0)"
html: dashboardLabels[number]
color: "#efefef"
style:
"text-align" : "center"
"font-size" : "20px"
"font-weight" : "100"

OK, now we got the job done. You should see the effect and download the project with this link:

http://share.framerjs.com/rx5fdtvs8bi7/

Thanks for reading : D

The last of last

At the time of writing, I just saw that I could rewrite the ChangeTime function in a easier way, we don’t need to create five Layers for the Number, we just need two, create and delete one of them each time. I will update the share link above while I finish the rewriting.

--

--