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