Search code examples
cashapelayeranchorpointcatransform3drotate

Can't change AnchorPoint for CAShapeLayer iOS Swift


Here is extract from my custom class, that drawing some graphics. Function drawTick() adds CAShapeLayer with blue rectangle to my GameTimer UIView:

class GameTimer: UIView {

 var tick = CAShapeLayer()
...

 init(){
   super.init(frame: CGRect(x: 0, y: 0, width: 200, height: 200)
 }
...

 func drawTick() {
 tick.path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 50, height: 50)).cgPath
 tick.fillColor = UIColor.blue.cgColor
 self.layer.addSublayer(tick)
 tick.anchorPoint = CGPoint(x: 0.5, y: 0.5)
 tick.position = CGPoint(x: bounds.midX, y: bounds.midY)
 tick.transform = CATransform3DMakeRotation(0.degreesToRadians, 0, 0, 1)
 }

...

}

extension Double {
  var degreesToRadians : CGFloat {
      return CGFloat(self) * CGFloat(M_PI) / 180.0
  }
}

enter image description here

Changing of rotation angle to 45 degrees by

tick.transform = CATransform3DMakeRotation(45.degreesToRadians, 0, 0, 1)

gives the next result:

enter image description here

Here I see, that the declared anchor point doesn't affect the tick layer - it should be at the center of blue rect. The rotation goes around point with coordinates (x: 0, y: 0) - the left top corner of blue rect - tick.position. The question - why declared anchorPoint position doesn't apply to the tick layer? It's behavior weird here assuming that the default position of anchorPoint should be already (x: 0.5, y: 0.5) without any manual override, but if I remove this override - nothing changes.


Solution

  • The tick layer doesn't have a size. The reason it looks correct is that the path isn't clipped to the bounds (i.e. is drawn outside the bounds).

    If you give the shape layer the same bounds as the circle's rectangle, then you'll be able to see the rotation around the center.