A Swift Perambulation through the World of CATransform3D: Translation, Rotation and Scaling (CALayer, iOS, Xcode)
Whereas a two-dimensional set of co-ordinates has an x-axis and y-axis, a three-dimensional set of co-ordinates as found in the CATransform3D Core Animation Functions has x, y and z axes. A z-axis comes outwards, or upwards, depending on which way you look at it.
This image comes from Wikimedia Commons:
But in Xcode we need to imagine something more like this
Translation
If we translate a CALayer or CAShapeLayer along the x-axis using CATransform3DMakeTranslation() it moves to the right (or left if negative) and if it is translated along the y-axis it moves down (or up if negative). If translated along both x and y axes it moves diagonally.
If the layer is translated along the z-axis it moves towards us (or away from us) but doesn't actually change in size, i.e. there is no perspective associated with a layer being translated along the z-axis, it can be thought of as equivalent to the changing of the layer's zPosition, although the zPosition doesn't actually change with the z-axis translation (neither does the anchorPointZ property change). This is because it is a distance moved along the z-axis rather than a relative index.
In Swift the above translations can be written:
If the layer is translated along the z-axis it moves towards us (or away from us) but doesn't actually change in size, i.e. there is no perspective associated with a layer being translated along the z-axis, it can be thought of as equivalent to the changing of the layer's zPosition, although the zPosition doesn't actually change with the z-axis translation (neither does the anchorPointZ property change). This is because it is a distance moved along the z-axis rather than a relative index.
In Swift the above translations can be written:
let layer = CALayer() layer.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 100, height: 100) layer.borderColor = UIColor.blackColor().CGColor layer.borderWidth = 1 self.view.layer.addSublayer(layer) let layerX = CALayer() layerX.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 100, height: 100) layerX.backgroundColor = UIColor.redColor().CGColor layerX.transform = CATransform3DMakeTranslation(200.0, 0.0, 0.0) self.view.layer.addSublayer(layerX) let layerY = CALayer() layerY.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 100, height: 100) layerY.backgroundColor = UIColor.blueColor().CGColor layerY.transform = CATransform3DMakeTranslation(0.0, 200.0, 0.0) self.view.layer.addSublayer(layerY) let layerXY = CALayer() layerXY.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 100, height: 100) layerXY.backgroundColor = UIColor.greenColor().CGColor layerXY.transform = CATransform3DMakeTranslation(200.0, 200.0, 0.0) self.view.layer.addSublayer(layerXY)
Rotation
Rotation treats the axes in a different way. A rotation around the x-axis is like watching a backwards flip or a gymnast on a horizontal bar. Rotating around the y-axis is akin to moving around a pole. While a z-axis rotation is like being twisted around.
Viewed in isolation a CALayer that rotates around the the x-axis appears to first shorten towards its centre then lengthen again. A y-axis rotation appears to narrow and then widen. While the z-axis does this (in a 45 degree rotation):
Viewed in isolation a CALayer that rotates around the the x-axis appears to first shorten towards its centre then lengthen again. A y-axis rotation appears to narrow and then widen. While the z-axis does this (in a 45 degree rotation):
func degree2radian(a:CGFloat)->CGFloat { let b = CGFloat(M_PI) * a/180 return b } let layer = CALayer() layer.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 100, height: 100) layer.borderColor = UIColor.blackColor().CGColor layer.borderWidth = 1 self.view.layer.addSublayer(layer) let layerZrotation = CALayer() layerZrotation.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 100, height: 100) layerZrotation.backgroundColor = UIColor.greenColor().CGColor layerZrotation.transform = CATransform3DMakeRotation(degree2radian(45), 0.0, 0.0, 1.0) self.view.layer.addSublayer(layerZrotation)Rotating along more than one axis at once is when things start to appear rotated in three-dimensions. If we rotate 90 degrees and share that 90 degree rotation equally between the z-axis and y-axis, or z-axis and y-axis equally the layer will appear transformed like this (90 degree rotation along y and z axes):
func degree2radian(a:CGFloat)->CGFloat { let b = CGFloat(M_PI) * a/180 return b } let layer = CALayer() layer.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 200, height: 200) layer.borderColor = UIColor.blackColor().CGColor layer.borderWidth = 1 self.view.layer.addSublayer(layer) let layerYZrotation = CALayer() layerYZrotation.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 200, height: 200) layerYZrotation.backgroundColor = UIColor.greenColor().CGColor layerYZrotation.transform = CATransform3DMakeRotation(degree2radian(90), 0.0, 1.0, 1.0) self.view.layer.addSublayer(layerYZrotation)It is the result of being pulled in two directions at once. While a three-way (90 degree) rotation across all axes will result in something like this:
func degree2radian(a:CGFloat)->CGFloat { let b = CGFloat(M_PI) * a/180 return b } let layer = CALayer() layer.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 200, height: 200) layer.borderColor = UIColor.blackColor().CGColor layer.borderWidth = 1 self.view.layer.addSublayer(layer) let layerXYZrotation = CALayer() layerXYZrotation.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 200, height: 200) layerXYZrotation.backgroundColor = UIColor.greenColor().CGColor layerXYZrotation.transform = CATransform3DMakeRotation(degree2radian(90), 1.0, 1.0, 1.0) self.view.layer.addSublayer(layerXYZrotation)In each instance the anchor point of the layers is set to the default position, which is the centre or (0.5, 0.5). (The x, y and z values are likewise proportional not absolute, as they were with the translation.)
Note: An anchor point of (1.0, 1.0) would result in a rotation around the bottom right corner and (0.0, 0.0) around the top left corner. Other rotation points such as (0.5, 1.0) are also an option.
Scaling
Scaling is different again in its implementation to rotation and translation. The values are a scale factor. So 1.0 means keep at current scale, while 2.0 is 2x scale, etc. In this image the scaling is x: 1.0, y: 2.0
let layer = CALayer() layer.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 200, height: 200) layer.borderColor = UIColor.blackColor().CGColor layer.borderWidth = 1 self.view.layer.addSublayer(layer) let layerXYscale = CALayer() layerXYscale.frame = CGRect(x: 20, y: CGRectGetMidX(self.view.frame), width: 200, height: 200) layerXYscale.backgroundColor = UIColor.greenColor().CGColor layerXYscale.zPosition = -1 layerXYscale.transform = CATransform3DMakeScale(1.0, 2.0, 0.0) self.view.layer.addSublayer(layerXYscale)But here the x value has been changed to 0.5:
As before all scaling occurs relative to the central (default) anchor point of the layer.
Note: a scale factor of zero on the x or y axis would result in a disappearance of the layer since the height or width would be reduced to zero.
Note: a scale factor of zero on the x or y axis would result in a disappearance of the layer since the height or width would be reduced to zero.
Nice tutorial
ReplyDeletePlease look at this link :
ReplyDeletehttp://stackoverflow.com/questions/41054948/how-to-avoid-tilt-flip-on-catransform3d-rotation-in-ios
Thanks for this info!
ReplyDelete