Learning notes for book iOS Animations by Tutorials.

The UIView transform property is of type CGAffineTransform, and is used to represent a two-dimensional rotation, scale, or translation. By changing it, you can rotate, scale or translate a view.

You can create a CGAffineTransform by these methods:

  • CGAffineTransformMakeRotation(CGFloat angle)
  • CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
  • CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)

The rotation and scale transforms are fairly self-explanatory—they rotate and scale a vector respectively. A translation transform just adds the specified x and y values to the vector—so if the vector represents a point, it moves the point.

You can combine new transform to an existing CGAffineTransform by using these methods:

  • CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
  • CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
  • CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)

or you can combine two existing CGAffineTransform into one by using:

  • CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);

Let’s see how to do a cube transition with CGAffineTransform.

Image-1Image-1

Look at the image. It looks like a cube that rotates around its center to reveal the next message on its sides. In fact, there are only two labels. One is login page and another is signup page. Let’s break it down. Now we only take care of login page label. It looks like this:
Image-2Image-2

It is obvious that we scale the label on its Y-axis. So let’s scale it by using the following code:

1
signInLbl.transform = CGAffineTransformMakeScale(1.0, 0.05)

As you can see, it scales the label on Y-axis from 1.0 to 0.05 (1.0 is the default). Let’s see the result:

Image-3Image-3

Well, looks like we still need do some thing. Here, the label just shrinks to the middle of Y-axis. Compared with our goal, it seems like that we need to move the shrinking destination down by half of label’s height.

1
2
let newLabelOffset = self.heading.frame.size.height / 2.0
CGAffineTransformMakeTranslation(0.0, newLabelOffset)

Here I didn’t write down “signInLbl.transform =”, because we can’t separately do the transforms. What we need is to combine the two CGAffineTransforms:

1
signInLbl.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, 0.05), CGAffineTransformMakeTranslation(0.0, newLabelOffset))

Now, We can get what we want for login page label.
The order of the transformations really matters the final results. If you change the sequence of scale and translate, you will get different results. The reason for this is that when you apply transforms sequentially in this way, the previous transforms affect the subsequent ones.
Let move on signup page label. It is easy now. The animation for signup page label is really like the reverse of signin page label animation. We first set its transform to:

1
signUpLbl.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, 0.05), CGAffineTransformMakeTranslation(0.0, -newLabelOffset))

And then set it back to normal. What is normal? Apple offered us a transform: CGAffineTransformIdentity. It is like the identity matrix in linear algebra.

1
signUpLbl.transform = CGAffineTransformIdentity

Okey, here is the full codes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
func changeHeadingText(label label: UILabel) {
if label.text == "Login Page" {
self.cubeTrasition(label: label, toText: "Signup Page")
} else {
self.cubeTrasition(label: label, toText: "Signin Page")
}
}

func cubeTrasition(label label: UILabel, toText: String){

let newLabel = UILabel(frame: label.frame)
newLabel.text = toText
newLabel.font = label.font
newLabel.textAlignment = label.textAlignment
newLabel.textColor = label.textColor
newLabel.backgroundColor = UIColor.clearColor()

let newLabelOffset = label.frame.size.height / 2.0
newLabel.transform = CGAffineTransformConcat(
CGAffineTransformMakeScale(1.0, 0.05), CGAffineTransformMakeTranslation(0.0, -newLabelOffset))

label.superview!.addSubview(newLabel)

UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseOut, animations: {
newLabel.transform = CGAffineTransformIdentity
label.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, 0.05), CGAffineTransformMakeTranslation(0.0, newLabelOffset))
}, completion: {_ in
label.text = newLabel.text;
label.transform = CGAffineTransformIdentity
newLabel.removeFromSuperview()
self.changeHeadingText(label: self.heading)
})