I'm attempting to create a CAShapeLayer animation that draws an outline around the frame of a UILabel. Here's the code:
func newQuestionOutline() -> CAShapeLayer {
let outlineShape = CAShapeLayer()
outlineShape.isHidden = false
let circularPath = UIBezierPath(roundedRect: questionLabel.frame, cornerRadius: 5)
outlineShape.path = circularPath.cgPath
outlineShape.fillColor = UIColor.clear.cgColor
outlineShape.strokeColor = UIColor.yellow.cgColor
outlineShape.lineWidth = 5
outlineShape.strokeEnd = 0
view.layer.addSublayer(outlineShape)
return outlineShape
}
func newQuestionAnimation() {
let outlineAnimation = CABasicAnimation(keyPath: "strokeEnd")
outlineAnimation.toValue = 1
outlineAnimation.duration = 5
newQuestionOutline().add(outlineAnimation, forKey: "key")
}
The animation performs as expected when running on the simulator for an iPhone 11 which is the device size that I used in the storyboard. However when running the project on a different device with different screen dimensions (like iPhone 8 plus) the shape is drawn out of place and not around the UILabel as it should be. I used autolayout to horizontally and vertically center the UILabel to the center of the view so the UILabel is centered no matter what device.
Any suggestions? Thanks in advance!
Cheers!
A shape layer is not a view, so it is not subject to auto layout. And any time you say something like roundedRect: questionLabel.frame
you are making yourself dependent on what questionLabel.frame
is at that moment, which is a huge mistake because that is exactly what is not determined until auto layout determines what the frame will be (and can change later if auto layout changes its mind due to changing conditions, such as rotation etc.)
There are two kinds of solution:
Host the shape layer in a view. Now you have something that is subject to autolayout. You will still need to redraw the shape layer whenever the view changes its frame, but you can detect that and perform the redraw.
Implement your view controller's viewDidLayoutSubviews
to detect that auto layout has just done its work. Respond by (for example) removing the shape layer and making a new one based on the current conditions.