使用 CGAffineTransform 旋轉或縮放 layer 時,設定 bounds & position 維持中心點位置
Published in
7 min readApr 12, 2023
當我們使用 CGAffineTransform 旋轉或縮放 CALayer 時,若想讓 layer 的中心點位置不變,記得要設定 layer 的 bounds & position。
以下我們舉一個例子說明,首先我們在黃色 view 上加入紅色正方形的 layer。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = .yellow
let path = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
let rectangleLayer = CAShapeLayer()
rectangleLayer.fillColor = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
rectangleLayer.path = path.cgPath
view.layer.addSublayer(rectangleLayer)
view
旋轉
對 rectangleLayer 呼叫 setAffineTransform 旋轉 10 度。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = .yellow
let path = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
let rectangleLayer = CAShapeLayer()
rectangleLayer.fillColor = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
rectangleLayer.path = path.cgPath
rectangleLayer.setAffineTransform(CGAffineTransform(rotationAngle: .pi / 180 * 10))
view.layer.addSublayer(rectangleLayer)
view
令人失望的,紅色正方形旋轉了,但它的位置有點偏移,它並不是繞著自己的中心點旋轉。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = .yellow
let path = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
let rectangleLayer = CAShapeLayer()
rectangleLayer.fillColor = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
rectangleLayer.path = path.cgPath
let boundingBox = path.cgPath.boundingBox
rectangleLayer.bounds = boundingBox
rectangleLayer.position = CGPoint(x: boundingBox.midX, y: boundingBox.midY)
rectangleLayer.setAffineTransform(CGAffineTransform(rotationAngle: .pi / 180 * 10))
view.layer.addSublayer(rectangleLayer)
view
問題出在 rectangleLayer 的 bounds 和 position 沒有設定。當我們加入以下程式設定後,rectangleLayer 即可正常地繞著自己的中心點旋轉。
let boundingBox = path.cgPath.boundingBox
rectangleLayer.bounds = boundingBox
rectangleLayer.position = CGPoint(x: boundingBox.midX, y: boundingBox.midY
縮放
將紅色正方形變成一半的大小,結果中心點位置跑掉了。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = .yellow
let path = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
let rectangleLayer = CAShapeLayer()
rectangleLayer.fillColor = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
rectangleLayer.path = path.cgPath
rectangleLayer.setAffineTransform(CGAffineTransform(scaleX: 0.5, y: 0.5))
view.layer.addSublayer(rectangleLayer)
view
設定 layer 的 bounds & position 後,layer 順利維持原本的中心點位置。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = .yellow
let path = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
let rectangleLayer = CAShapeLayer()
rectangleLayer.fillColor = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
rectangleLayer.path = path.cgPath
let boundingBox = path.cgPath.boundingBox
rectangleLayer.bounds = boundingBox
rectangleLayer.position = CGPoint(x: boundingBox.midX, y: boundingBox.midY)
rectangleLayer.setAffineTransform(CGAffineTransform(scaleX: 0.5, y: 0.5))
view.layer.addSublayer(rectangleLayer)
view