Whats the Swift animate WithDuration syntax? - swift

I'm porting an older app over to Xcode 7 beta and I'm getting an error on my animations:
Cannot invoke 'animateWithDuration' with an argument list of type
'(Double, delay: Double, options: nil, animations: () -> _,
completion: nil)'
Here's the code:
UIView.animateWithDuration(0.5, delay: 0.3, options: nil, animations: {
self.username.center.x += self.view.bounds.width
}, completion: nil)
This works in Xcode 6 so I'm assuming this is an update in Swift. So my question is:
What's the Swift 3 syntax for animateWithDuration?

Swift 3/4 Syntax
Here's an update with the Swift 3 Syntax:
UIView.animate(withDuration: 0.5, delay: 0.3, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
self.username.center.x += self.view.bounds.width
}, completion: nil)
If you need to add a completion handler just add a closure like so:
UIView.animate(withDuration: 0.5, delay: 0.3, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
// animation stuff
}, completion: { _ in
// do stuff once animation is complete
})
Old Answer:
It turns out it's a very simple fix, just change options: nil to options: [].
Swift 2.2 Syntax:
UIView.animateWithDuration(0.5, delay: 0.3, options: [], animations: {
self.username.center.x += self.view.bounds.width
}, completion: nil)
What changed?
Swift 2 got rid of the C-Style comma-delimited list of options in favor of option sets (see: OptionSetType). In my original question, I passed in nil for my options, which was valid prior to Swift 2. With the updated syntax, we now see an empty option list as an empty set: [].
An example of animateWithDuration with some options would be this:
UIView.animateWithDuration(0.5, delay: 0.3, options: [.Repeat, .CurveEaseOut, .Autoreverse], animations: {
self.username.center.x += self.view.bounds.width
}, completion: nil)

Swift 3, 4, 5
UIView.animate(withDuration: 1.5, delay: 0.05 * Double(index), usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations: {
cell.transform = CGAffineTransform(translationX: 0, y: 0)
}, completion: nil)

Swift 3 Syntax with completion block
UIView.animate(withDuration: 3.0 , delay: 0.25, options: .curveEaseOut, animations: {
// animation
}, completion: { _ in
// completion
})

Swift 2
UIView.animateWithDuration(1.0, delay: 0.1, options: [.Repeat, .CurveEaseOut, .Autoreverse], animations: {
// animation
}, completion: { finished in
// completion
})
Swift 3, 4, 5
UIView.animate(withDuration: 1.0, delay: 0.1, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
// animation
}, completion: { finished in
// completion
})

Related

How can I repeat chained animation in Swift?

I would like to animate the whole chain for forever.
UIView.animate(withDuration: 2.0, delay: 0.2, options: .curveEaseOut, animations: {
self.circleImageView.transform = CGAffineTransform(scaleX: 9, y: 9)
}) { (_) in
UIView.animate(withDuration: 2.0, delay: 0.2, options: .curveEaseIn, animations: {
self.circleImageView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
}, completion: nil)
}
You can wrap the two animations within a keyframe animation. Then you can .repeat that:
UIView.animateKeyframes(withDuration: 4.4, delay: 0, options: .repeat, animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 2.0/4.4) {
self.circleImageView.transform = .init(scaleX: 9, y: 9)
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 2.0/4.4) {
self.circleImageView.transform = .init(scaleX: 0.01, y: 0.01)
}
})
Wrap it up inside a method:
func repeatingAnimation() {
UIView.animate(withDuration: 2.0, delay: 0.2, options: .curveEaseOut, animations: {
self.circleImageView.transform = CGAffineTransform(scaleX: 9, y: 9)
}) { (_) in
UIView.animate(withDuration: 2.0, delay: 0.2, options: .curveEaseIn, animations: {
self.circleImageView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
}, completion: { [weak self] _ in
self?.repeatingAnimation()
})
}
}

Fade in chain animations don't work: only view fades in

I'm trying to use a fade in animation chain to fade in my objects in order. First I make the view fade in, then the rest of the labels should follow suit. The labels are in a stack view, which has an alpha of 1.0. I made sure that all of the other alpha values started at zero. Here is my function:
func fadeIn() {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.view.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.gameOverLabel.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.scoreLabel.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.highScoreLabel.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.restartButton.alpha = 1.0
}, completion: nil)
//breakpoint set here
}
})
}
})
}
})
}
})
}
I set a breakpoint after all of the animations were completed(as shown above) and all alpha values were 1.0. However, the device just gives me a blank, white screen. What is going on?
P.S. The function is called immediately after this view controller is presented:
view.present(vc, animated: false, completion: {
vc.fadeIn()
})
Try adding the .layoutSubviews option to your animations. Like this:
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.layoutSubviews, animations: {
// animate here
})
From apple's docs this option does this:
Lay out subviews at commit time so that they are animated along with their parent.
Might be that the subviews aren't laid out yet at commit time due to being presented.

Swift only call recursive function X times

I have a function I am using to animate 4 UILabels. The animation is chained and I am trying to reduce repeated code by creating a recursive function that accepts the label as an argument, on completion calls itself with the next label.
fileprivate func handleAnimations(firstLabel: UILabel, secondLabel: UILabel) -> Void {
UIView.animate(withDuration: 1, delay: 2, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
firstLabel.alpha = 1
}) { (_) in
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
secondLabel.alpha = 1
}) { (_) in
UIView.animate(withDuration: 0.5, delay: 3, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
firstLabel.alpha = 0
secondLabel.alpha = 0
}, completion: { (_) in
self.handleAnimations(firstLabel: self.introTextLabelThree, secondLabel: self.introTextLabelFour)
})
}
}
}
Is this the best way to achieve this? If so, how I prevent the final complete block calling itself over and over with the final 2 labels?
The effect I am trying to achieve is:
labelOne - fades in
labelTwo - fades in
labelOne and labelTwo - fade out
labelThree - fades in
labelFour - fades in
labelThree and labelFour - fade out
After labelThree and labelFour I would be looking to implement another function call.
Do not do this. Please use animateKeyframes. This will allow you to properly chain animations without the dreaded pyramid of doom.
UIView.animateKeyframes(withDuration: 5.0, delay: 0, options: [.calculationModeCubic], animations: {
// Add animations
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0/6.0, animations: {
self.introTextLabel.alpha = 1
})
UIView.addKeyframe(withRelativeStartTime: 1.0/6.0, relativeDuration: 1.0/5.0, animations: {
self.introTextLabelTwo.alpha = 1
})
UIView.addKeyframe(withRelativeStartTime: 2.0/6.0, relativeDuration: 1.0/5.0, animations: {
self.introTextLabel.alpha = 0
self.introTextLabelTwo.alpha = 0
})
UIView.addKeyframe(withRelativeStartTime: 3.0/6.0, relativeDuration: 1.0/5.0, animations: {
self.introTextLabelThree.alpha = 1
})
UIView.addKeyframe(withRelativeStartTime: 4.0/6.0, relativeDuration: 1.0/5.0, animations: {
self.introTextLabelFour.alpha = 1
})
UIView.addKeyframe(withRelativeStartTime: 5.0/6.0, relativeDuration: 1.0/5.0, animations: {
self.introTextLabelThree.alpha = 0
self.introTextLabelFour.alpha = 0
})
}, completion:{ _ in
// fire off whatever other method you want here
})

viewDidAppear() running on every click

I am trying to create an animation slide in for two textfields and a label. However for some reason the viewDidAppear() function runs every time you attempt to click the textfield, causing them to continue to animate. Does anyone have any ideas?
This is my code for the function:
override func viewDidAppear(animated: Bool)
{
//Some Code here
UIView.animateWithDuration(1.5, delay: 0.5,
usingSpringWithDamping: 0.3,
initialSpringVelocity: 0.5,
options: [], animations: {
self.Email.center.x += 475
self.Password.center.x -= 400
}, completion: nil)
UIView.animateWithDuration(2.0, delay: 2.0,
options: [],
animations: {
self.LoginButton.alpha = 1.0
}, completion: nil)
UIView.animateWithDuration(1.5, delay: 0.5,
usingSpringWithDamping: 0.3,
initialSpringVelocity: 0.5,
options: [], animations: {
self.LoginL.center.y += 100
}, completion: nil)
}
As we found out the problem was with the UIViewController's life cycle - it was needed to call super.viewDidAppear(animated).
try to run it viewWillAppear instead, your animation will be run only when your screen loads for the first time.

Showing error while using 'animateWithDuration'

I am new in Swift so could not figure out the problem , Please guide me
using It like
UIView.animateWithDuration(duration, delay: 0.0, options: option, animations: { () -> Void in
self.btnCallButton.hidden = true
}, completion: nil)
and it showing following error
Cannot invoke 'animateWithDuration' with an argument list of type '(Float, delay: FloatLiteralConvertible, options: UIViewAnimationOptions, animations: () -> Void, completion: NilLiteralConvertible)'
please give the required suggestion and also provide some links which describe the blocks in swift
Like this:
UIView.animate(withDuration: 0.35) {
// animate things
return
}
Add return at end of closure as
UIView.animate(withDuration: duration, delay: 0.0, options: option, animations: { () -> Void in
self.btnCallButton.hidden = true
return
}, completion: nil)
Hidden is not animatable in Swift. If you want to hide/show via fade in/out use the following code for fadeout
UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: {
self.btnCallButton.isHidden = false
self.btnCallButton.alpha = 0.0
}, completion: { finished in
self.btnCallButton.isHidden = true
})
and following for fadein
UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: {
self.btnCallButton.isHidden = false
self.btnCallButton.alpha = 1.0
}, completion: { finished in
})