Swift Transforms

Eduardo Irías
Weeronline
Published in
5 min readAug 27, 2020

An affine transformation allows a UIView to be translated, scaled, rotated or skewed. UIViews have a CGAffineTransform property called transform.

What are affine transformations? Affine transforms are transformations that preserves proportions and collinearity between points.

Transform Matrix

The transform matrix of UIViews are represented by a 3 by 3 matrix. All the transformations are applied to the UIView’s bound center.

Sample of a transform matrix

It’s possible to get and set a UIView’s transform property or matrix values.

view.transformview.transform.a

Identity matrix

An identity matrix is a square matrix with ones placed diagonally and zero in all the other elements. This is the default value of the UIView’s transform property.

Sample of an identity matrix

The identity matrix is useful to reset a view’s position, rotation or scale.

view.transform = CGAffineTransform.identity

Transform objects have a Boolean property isIdentity. It’s used to check if a view’s transform is the identity transform.

view.transform.isIdentity

Translate Matrix

To change a UIView’s position, a translate matrix is applied to the transform matrix. This will change the values tx and ty values of the transform matrix.

CGAffineTransform’s have a function translateBy(x:y:) and an initializer CGAffineTransform(translationX: , y: )

view.transform = view.transform.translatedBy(x: 100, y: 100)
view.transform = CGAffineTransform(translationX: 100, y: 100)
Translate example

This function creates an affine transform matrix translating the current transform with the provided values.

It’s also possible to individually manipulate tx and ty values of the transform matrix.

view.transform.tx = 100
view.transform.ty = 100

Scale Matrix

A scale matrix is used to scale a UIView’s width and height. To change the scaling of a UIView a scaling matrix is applied to the transform matrix. The scale matrix changes the a and d values of the transform, where a is the xScale and d the yScale. The default values of a and d are 1 and 1.

To scale a view, it’s possible to use the function, scaleBy(x:y:) and an initializer CGAffineTransform(scaleX: , y: )

view.transform = view.transform.scaledBy(x: 2, y: 2)
view.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)

Scaling by both axis by 2, will double the image size.

Scale example

It’s also possible to individually manipulate a and d values of the transform matrix.

view.transform.a = 4.0
view.transform.d = 3.0

Rotation Matrix

To rotate a UIView a rotation matrix is applied to the transform matrix. The rotation matrix affects the a, b, c and d properties of the transform.

To rotate a view it’s possible to use the function, rotated(by:) and an initializer CGAffineTransform(rotationAngle: )

view.transform = view.transform.rotated(by: CGFloat.pi)
view.transform = CGAffineTransform(rotationAngle: angle)
Rotation example

It’s possible to rotate a view, by setting the abcd values of the matrix.

let angle: CGFloat = 45.0 * CGFloat.pi / 180.0view.transform.a = cos(angle)view.transform.b = sin(angle)view.transform.c = -sin(angle)view.transform.d = cos(angle)

Skew

Skewing a view is possible by modifying the b and c values of the matrix.

let angle: CGFloat = 45.0 * CGFloat.pi / 180.0view.transform.b = cos(angle)
Skew in B
let angle: CGFloat = 45.0 * CGFloat.pi / 180.0view.transform.c = cos(angle)
Skew in C

Concatenation

Performing multiple transformations to a UIView, might have unexpected outcomes.

let angle: CGFloat = 45.0 * CGFloat.pi / 180.0view.transform = CGAffineTransform(rotationAngle: angle)view.transform = CGAffineTransform(translationX: 10.0, y: 0.0)view.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)

This code seems to rotate a view, translate it and later scale it. The final outcome of this algorithm is just a scaled UIView. This is because the transform is always reassigned, thus it’s removing the value of the previous matrix.

To assign multiple transformations on a view, it’s necessary to concatenate the transformation matrixes. The CGAffineTransform has a method:

func concatenating(_ t2: CGAffineTransform) -> CGAffineTransform

The concatenating function receives t2 as parameter. It multiplies the current transform with t2 and return the result of multiplication matrix.

let rotationMatrix = CGAffineTransform(rotationAngle: angle)let translationMatrix = CGAffineTransform(translationX: 10.0, y: 0.0)view.transform = rotationMatrix.concatenating(translationMatrix)

It’s important to remember some properties of matrix multiplications.

a.b != b.a

let rotationMatrix = CGAffineTransform(rotationAngle: angle)let translationMatrix = CGAffineTransform(translationX: 10.0, y: 0.0)view.transform = translationMatrix.concatenating(rotationMatrix)

This code first translates the view and then rotates it. The rotation is calculated based on the UIView’s center. That’s the reason why the position seems to be off. The order of products is important when multiplying matrixes.

Conclusion

(/^▽^)/

It’s easier to perform translations, scaling or rotations to views using transforms in Swift. All the UIView objects have a transform property. It’s also possible calculate the matrix values and assign the resulting matrix to a UIView’s transform.

--

--

Eduardo Irías
Weeronline

Guess What? I'm not a Robot, but I'm allergic to H2O. I love music, monsters and fables.