1
votes

In one of my ViewControllers, I have addStatus(), which is pasted below, in my viewDidLoad. I expect the lineWidth of this circle to animate, but it doesn't seem to be doing so. In my search for why this might be, I found this part of Apple's documentation on Animating Layer Content. The part that I thought to be important noted here:

If you want to use Core Animation classes to initiate animations, you must issue all of your Core Animation calls from inside a view-based animation block. The UIView class disables layer animations by default but reenables them inside animation blocks. So any changes you make outside of an animation block are not animated. Listing 3-5 shows an example of how to change a layer’s opacity implicitly and its position explicitly. In this example, the myNewPosition variable is calculated beforehand and captured by the block. Both animations start at the same time but the opacity animation runs with the default timing while the position animation runs with the timing specified in its animation object.

When I looked up why this might not be animating, I read this piece and assumed that it meant I should place my CAAnimation inside of a UIView animation block. This function worked fine in a blank application without the animation block when placed in the rootViewController, but does not seem to animate when in my secondary viewController in this app. Any tips would be wonderfully helpful. Thanks!

func addStatus() {

        UIView.animateWithDuration( NSTimeInterval.infinity, animations: { () -> Void in

            let patientZeroIndicator = CAShapeLayer()

            let radius:CGFloat = 20.0
            let center:CGPoint = CGPointMake(self.view.frame.width - radius - 10, radius + 10)
            let startAngle = 0.0
            let endAngle = 2.0 * Double(M_PI)

            patientZeroIndicator.lineWidth = 10.0
            patientZeroIndicator.fillColor = UIColor(netHex: cs_red).CGColor
            patientZeroIndicator.strokeColor = UIColor.whiteColor().CGColor
            patientZeroIndicator.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true).CGPath
            self.view.layer.addSublayer(patientZeroIndicator)

            // Create a blank animation using the keyPath "cornerRadius", the property we want to animate
            let pZeroAnimation = CABasicAnimation(keyPath: "lineWidth")

            // Define the parameters for the tween
            pZeroAnimation.fromValue = 10.0
            pZeroAnimation.toValue = 5.0
            pZeroAnimation.autoreverses  = true
            pZeroAnimation.duration = 3.0
            pZeroAnimation.repeatDuration = CFTimeInterval.infinity
            pZeroAnimation.timingFunction = CAMediaTimingFunction(controlPoints: 0.25, 0, 0.75, 1)

            // Finally, add the animation to the layer
            patientZeroIndicator.addAnimation(pZeroAnimation, forKey: "lineWidth")
        })
    }
1
For anyone googling here, I would urge you to just subclass the view. This is tremendously simpler, easier and quicker than trying to do it from a view controller. Many examples online ... stackoverflow.com/a/58681566/294884Fattie

1 Answers

8
votes

in my viewDidLoad.

That is your problem. The viewDidLoad method runs before the view has been added to a window. You can't add animations to a view unless it's in a window. Call addStatus in viewDidAppear: instead.

Also, don't create new layers in your animation block. Create the layer in viewDidLoad.