iOS CGAffineTransform

Affine transformation


    var containerView: UIView = {
        let v = UIView()
        v.backgroundColor = .green

        // Whether to render the back of the view. If you rotate 180 degrees along the X or y axis during the 3D transformation, you will go to the back of the view
        // A mirrored view is displayed when true
        // Do not render or display when false
        v.layer.isDoubleSided = true
        return v
    }()

    containerView.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
    let affine = CGAffineTransform(rotationAngle: .pi / 4)
    // Layer affineTransform corresponds to view transform
    containerView.layer.setAffineTransform(affine)
    view.addSubview(containerView)
Copy the code

CGAffineTransform is a structure


public struct CGAffineTransform {

    public var a: CGFloat

    public var b: CGFloat

    public var c: CGFloat

    public var d: CGFloat

    public var tx: CGFloat

    public var ty: CGFloat

    public init(a)

    public init(a: CGFloat.b: CGFloat.c: CGFloat.d: CGFloat.tx: CGFloat.ty: CGFloat)
}
Copy the code

Structs are value references that are placed in stack space and cannot be modified using let assignment, so you can initialize an object that contains translation, rotation, and scaling using a chain syntax call at initialization time


let affine = CGAffineTransform(rotationAngle: .pi / 4).scaledBy(x: 2, y: 2).translatedBy(x: 100, y: 100)
Copy the code

Since the scaledBy() function is not open source, but it returns a CGAffineTransform, you can guess that the function is an initialization process, so we’ll use this demo to experiment

struct ZPHTest {
    var x: Int = 0
    var y: Int = 0
}

extension ZPHTest {
    func rotaion(angle: Int) -> ZPHTest {
        return ZPHTest(x: self.x, y: angle)
    }

    func scale(angle: Int) -> ZPHTest {
        return ZPHTest(x: angle, y: self.y)
    }
}

let t = ZPHTest(x: 10, y: 10).rotaion(angle: 20)
print(t) // ZPHTest(x: 10, y: 20)

// It looks like this
Copy the code

3 d transform


    var trans = CATransform3DIdentity
    trans.m34 = -1.0 / 800.0
    trans = CATransform3DRotate(trans, .pi / 4.0.1.0)
    containerView.layer.transform = trans

Copy the code

During transformation, there is a far-to-near visual effect called the vanishing point, which corresponds to the Transform3D property M34.

On the back

When the rotate is.pi/2, which is 90 degrees, we can’t see the view because the view has no thickness. When the rotate is.pi, which is the back side, we see the mirror view. We can use isDoubleSided to disable the back side

The actual location of the transform

Layer transform changes,frame changes.

Simple implementation of rotation


var v1: UIImageView = {
    let v = UIImageView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
    v.image = UIImage(named: "321")
    return v
    }()

var v2: UIImageView = {
    let v = UIImageView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
    v.image = UIImage(named: "123")
    return v
}()

override func viewDidLoad(a) {
    super.viewDidLoad()

    view.addSubview(v1)
    let animation = CABasicAnimation()
    animation.keyPath = "transform.rotation.y"
    animation.fromValue = 0
    animation.toValue = Double.pi / 2
    animation.duration = 2
    animation.delegate = self
    animation.repeatCount = 1
    animation.setValue("v1", forKey: "v1")
    v1.layer.add(animation, forKey: nil)}func animationDidStop(_ anim: CAAnimation.finished flag: Bool) {

    if anim.value(forKey: "v1") as? String = = "v1" {
        print("animationDidStop")
        v1.removeFromSuperview()

        v2.layer.transform = CATransform3DMakeRotation(-.pi / 2.0.1.0)
        view.addSubview(v2)
        let animation = CABasicAnimation()
        animation.keyPath = "transform.rotation.y"
        animation.fromValue = -Double.pi / 2
        animation.toValue = 0
        animation.duration = 2
        animation.delegate = self
        animation.repeatCount = 1
        v2.layer.add(animation, forKey: nil)}else {
        v2.layer.transform = CATransform3DMakeRotation(0.0.1.0)}}Copy the code

The topic outside

I saw 3d transformation originally because of the requirement of card rotation on the back. After reading some articles, I found that the system has already provided corresponding API [😂].


/// UIView class method
/// Rotate from front to back
@available(iOS 4.0.*)
    open class func transition(from fromView: UIView.to toView: UIView.duration: TimeInterval.options: UIView.AnimationOptions= [].completion: ((Bool) - >Void)? = nil)
Copy the code

Using this method. Do not have to calculate their own rotation Angle and so on. IOSNB!


reference

IOS core animation advanced skills