How to apply multiple transforms in Swift

IosSwiftUiviewTransformCgaffinetransform

Ios Problem Overview


I would like to apply multiple transforms to a UIView (or subclass of UIView), such as translate, rotate, and scale. I know that two transforms can be applied with CGAffineTransformConcat, but how do I do it if I have three or more transforms?

I have seen these questions:

but these questions are asking something different, and the given answers just talk about applying two transforms with CGAffineTransformConcat. Also, they use Objective-C rather than Swift.

Ios Solutions


Solution 1 - Ios

You can apply multiple transforms by stacking them on top of each other.

var t = CGAffineTransform.identity
t = t.translatedBy(x: 100, y: 300)
t = t.rotated(by: CGFloat.pi / 4)
t = t.scaledBy(x: -1, y: 2)
// ... add as many as you want, then apply it to to the view
imageView.transform = t

Or more compactly (but not necessarily as readable):

imageView.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 300).rotated(by: CGFloat.pi / 4).scaledBy(x: -1, y: 2)

This series of transforms produces the image on the right:

enter image description here

Thanks to this answer for teaching me how to do it.

#Notes

  • The order in which you apply the transforms matters. For example, if the transforms were done in the opposite order it would produce the following result.

      t = t.scaledBy(x: -1, y: 2)
      t = t.rotated(by: CGFloat.pi / 4)
      t = t.translatedBy(x: 100, y: 300)
    

enter image description here

See also

This answer has been tested with Swift 4

Solution 2 - Ios

In Swift 3, these have been replaced by functions on CGAffineTransform itself, which can be chained.

extension CGAffineTransform {
    public func translatedBy(x tx: CGFloat, y ty: CGFloat) -> CGAffineTransform
    public func scaledBy(x sx: CGFloat, y sy: CGFloat) -> CGAffineTransform
    public func rotated(by angle: CGFloat) -> CGAffineTransform
}

so for example

let transform = CGAffineTransform(scaleX: 1.0, y: 3.0).translatedBy(x: 12, y: 9).rotated(by: 17.0)

Solution 3 - Ios

the trick is that view.transform.translatedBy(x: 100, y: 100) is NOT changing view.transform. it just returns the new CGAffineTransform that you need to ASIGN back to view.transform.

view.transform = view.transform.translatedBy(x: 100, y: 100)

You can do that as many times as you need or in a sequence

view.transform = view.transform.translatedBy(x: 100, y: 100).rotated(by: CGFloat.pi / 2).scaledBy(x: 2, y: 2)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSuragchView Question on Stackoverflow
Solution 1 - IosSuragchView Answer on Stackoverflow
Solution 2 - IosTyler SheafferView Answer on Stackoverflow
Solution 3 - IosgiacoderView Answer on Stackoverflow