Search code examples
iosswiftuiviewcore-graphicscore-animation

Swift: Core Animation not animating


I'm a noobie when it comes to Core Animation. I'm trying to implement simple animation where UILabel moves from point A to point B. I have the following code that I got from an animation code example but I can't get this to work. The label simply doesnt move. What am I doing wrong?

let frame = self.view.frame
let blueBox = UIView(frame: frame)
blueBox.backgroundColor = UIColor(red:  46/255, green: 83/255, blue: 160/255, alpha: 1.0)

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 400))
label.center = CGPoint(x: frame.size.width/2, y: frame.size.height/2)
label.textAlignment = .center
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0

label.layer.position = label.center

var attrsA = [NSFontAttributeName: UIFont(name: "LemonMilk", size: 92), NSForegroundColorAttributeName: UIColor.white]
var a = NSMutableAttributedString(string:"Hello\n", attributes:attrsA)
var attrsB =  [NSFontAttributeName: UIFont(name: "LemonMilk", size: 38), NSForegroundColorAttributeName: UIColor.white]
var b = NSAttributedString(string:"World", attributes:attrsB)
a.append(b)


label.attributedText = a

let theAnimation = CABasicAnimation(keyPath: "position");
theAnimation.fromValue = [NSValue(cgPoint: CGPoint(x: screenWidth/2, y: screenHeight/2))]
theAnimation.toValue = [NSValue(cgPoint: CGPoint(x: 100.0, y: 100.0))]
theAnimation.duration = 3.0;
theAnimation.autoreverses = false //true - reverses into the initial value either smoothly or not
theAnimation.repeatCount = 2

blueBox.addSubview(label)

view.addSubview(blueBox)
label.layer.add(theAnimation, forKey: "animatePosition");

Solution

  • First: You cannot call addSubview on label and add(animation:) on label.layer in the same breath. You can only animate a view that is already in the view hierarchy. In other words, even if everything about your code were fine, you are calling add(animation:) too soon. Try introducing a delay.

    Second: These lines are bogus:

    theAnimation.fromValue = [NSValue(cgPoint: CGPoint(x: screenWidth/2, y: screenHeight/2))]
    theAnimation.toValue = [NSValue(cgPoint: CGPoint(x: 100.0, y: 100.0))]
    

    Neither the fromValue nor to toValue can be an array. Get rid of those braces. And in Swift 3.0.1 and later, you don't need to coerce to NSValue either. So:

    theAnimation.fromValue = CGPoint(x: screenWidth/2, y: screenHeight/2)
    theAnimation.toValue = CGPoint(x: 100.0, y: 100.0)
    

    Third: What is the fromValue even for? If you want to animate from where the label already is, simply omit the fromValue.

    Thus, I modified your code to end like this, and I saw animation:

    label.attributedText = a
    blueBox.addSubview(label)
    view.addSubview(blueBox)
    delay(1) {
        let theAnimation = CABasicAnimation(keyPath: "position");
        theAnimation.toValue = CGPoint(x: 100.0, y: 100.0)
        theAnimation.duration = 3.0;
        theAnimation.autoreverses = false //true - reverses into the initial value either smoothly or not
        theAnimation.repeatCount = 2
        label.layer.add(theAnimation, forKey: "animatePosition");
    }