1

I have a loginViewController that pops up persistently when a user is not logged in. I would like to animate the background of this window. I have tried two methods, UIViewAnimateWithDuration by adding a subview, and CABasicAnimation by adding a sublayer. Neither animation is running. The sublayer and subview are being drawn but they're not animated.

The first animation is animateWithDuration. It attempts to move the drawn rectangle to a random point on it's y-axis. The second animation is CABasicAnimation for opacity, changing the alpha of the drawn rectangle from 1 to 0. It doesn't matter to me whether I use view animation or layer animation both would suffice but neither are clicking.

func makeBackground() -> UIView {

    let backRect = UIView()
    backRect.frame = self.view.bounds
    backRect.backgroundColor = backgroundColor

    let floater2 = UIView(frame: CGRectMake(25.0, 0.0, 25, 25))
    floater2.backgroundColor = backgroundColor
    floater2.layer.borderWidth = 1.0
    floater2.layer.borderColor = lowColor.CGColor
    floater2.alpha = 0.0

    backRect.addSubview(floater2)

    UIView.animateWithDuration(2.0, delay: 0.0, options: .Repeat, animations: { () -> Void in

        let randomY = CGFloat(arc4random_uniform(568))            
        floater2.frame.origin.y = randomY

    }, completion: nil)



    let floater1 = CALayer()
    floater1.frame = CGRectMake(0.0, 0.0, 25, 25)
    floater1.backgroundColor = UIColor.redColor().CGColor

    let animation = CABasicAnimation(keyPath: "opacity")
    animation.fromValue = 1.0
    animation.toValue = 0.0
    animation.repeatCount = 100
    animation.duration = 2.0

    floater1.addAnimation(animation, forKey: "opacity")

    backRect.layer.addSublayer(floater1)

    return backRect
}

And then I assign the result of the function to a variable when presenting the login view controller:

        var loginViewController = PFLogInViewController()
        loginViewController.delegate = self
        loginViewController.fields = PFLogInFields.Default
            | PFLogInFields.Facebook
            | PFLogInFields.Twitter

        loginViewController.logInView?.backgroundColor = backgroundColor

        var bg = self.makeBackground()

        loginViewController.logInView?.addSubview(bg)
        loginViewController.logInView?.sendSubviewToBack(bg)

enter image description here

Phil Andrews
  • 5,501
  • 6
  • 32
  • 61

1 Answers1

1

The problem with this code:

backRect.addSubview(floater2)
UIView.animateWithDuration(2.0, delay: 0.0, options: .Repeat, animations: { () -> Void in
    floater2.frame.origin.y = randomY

...is that you're trying to animate something that isn't part of the render tree yet. You need to provide a "heartbeat" after addSubview so that floater2 is part of the render tree - that is, it is actually in the interface - before you start animating it. A short delay will do:

backRect.addSubview(floater2)
delay(0.1) {
    UIView.animateWithDuration(2.0, delay: 0.0, options: .Repeat, animations: { () -> Void in
        floater2.frame.origin.y = randomY

(where delay is, or is similar to, my utility function here: https://stackoverflow.com/a/24318861/341994).

The problem with your layer animation is parallel. You can't animate a layer until it is in the render tree. In fact, since a view is a layer and since view animation actually is layer animation, it's identically the same issue.

Community
  • 1
  • 1
matt
  • 447,615
  • 74
  • 748
  • 977