Setting options in animateWithDuration in Swift 2 - uiview

I am animating a textfield with the following code:
UIView.animateWithDuration(0.5, delay: 0.4,
options: .Repeat | .Autoreverse | .CurveEaseOut, animations: {
self.password.center.x += self.view.bounds.width
}, completion: nil)
I get the error Could not find member 'Repeat'
The code only works if I set only one option. Why is it not letting me set multiple options?

The syntax for combining OptionSetType has changed, you will be able to do it like this:
UIView.animateWithDuration(0.5, delay: 0.4,
options: [.Repeat, .CurveEaseOut, .Autoreverse], animations: {
self.password.center.x += self.view.bounds.width
}, completion: nil)

Related

UIview resets to initial position after animation step complete

I need to rotate clock view with some angle. But second step of animation starting at the initial position, when i need to continue its with the new one.
UIView.animate(withDuration: 0.8, delay: 0, options: [.beginFromCurrentState], animations: {
UIView.setAnimationRepeatCount(5)
self.clock.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi/4), 0, 0, 1)
}, completion: nil)
When i'm trying to do some animation in completion block it doesn't trigger. And after second pressing the button - animation doesn't launching at all, but the console is displaying "true".
#IBAction func flip(_ sender: Any) {
UIView.animate(withDuration: 0.2, animations: {
self.FirstView.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi), -1, 1, 0)
}, completion: { finished in
print(finished)
UIView.animate(withDuration: 0.2, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: [], animations: {
self.FirstView.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi), -1, 1, 0)
}, completion: nil)
})}
P.S. Sorry for my poor English

Cannot get closure syntax to work in swift 4

I've tried every syntax variation that I can, but the completion handler always activates before the end of the animation. I think I'm supposed to replace Bool with something else?
UIView.transition(with: swipeForPicturesIndicator,
duration: 1,
options: .curveEaseIn,
animations: {
self.swipeForPicturesIndicator.alpha = 0
},
completion: { (Bool) -> Void in
self.swipeForPicturesIndicator.isHidden = true
self.swipeForPicturesIndicator.alpha = 0.8
})
The Bool value indicates wether the animation was finished when the completion block was called. If that value is false it means your animation was interrupted.
You should use probably animate instead of transition
UIView.animate(withDuration: 1,
delay: 0,
options: .curveEaseIn,
animations: {
self.swipeForPicturesIndicator.alpha = 0
}) { (completed) in
/* Optionally check if animation finished */
self.swipeForPicturesIndicator.isHidden = true
self.swipeForPicturesIndicator.alpha = 0.8
}
Try this
self.swipeForPicturesIndicator.alpha = 0
UIView.transition(with: swipeForPicturesIndicator,
duration: 1,
options: .curveEaseIn,
animations: {
self.swipeForPicturesIndicator.alpha = 0.8
},
completion: nil)
You may want to use animate instead of transition:
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseIn, animations: {
self.swipeForPicturesIndicator.alpha = 0
}) { (success) in
self.swipeForPicturesIndicator.isHidden = true
self.swipeForPicturesIndicator.alpha = 0.8
}

Swift skips one animation (UIView.animate)

I have a logoImage on a view, animating the constraints.
The constraints animated are width and height ; going from original state of 220.0 to 240.0 (works fine) and THEN I would like to make it go back to 220.0 but the animation is skipped and the image goes directly back in 0.1second to 220.0.
Here is the code of the animation
func animate() {
self.imageHeightConstraint.constant = 240.0
self.imageWidthConstraint.constant = 240.0
UIView.animate(withDuration: 1.0,
delay:0.0,
options: .curveEaseIn,
animations:{
self.logoImage.layoutIfNeeded()
}, completion: { (finished: Bool) -> Void in
self.imageHeightConstraint.constant = 220.0
self.imageWidthConstraint.constant = 220.0
UIView.animate(withDuration: 2.0,
delay:0.0,
options: .curveEaseIn,
animations: {
self.logoImage.layoutIfNeeded()
})
})
}
Thanks in advance for any help I could get! ;-)
You need to call self.logoImage.setNeedsLayout() within your completion block, before you re-set the constants. This since you need to invalidate the current layout of the receiver and trigger a layout update during the next update cycle.
Try this code instead and it will work for you:
func animate() {
self.imageHeightConstraint.constant = 240.0
self.imageWidthConstraint.constant = 240.0
UIView.animate(withDuration: 1.0,
delay:0.0,
options: .curveEaseIn,
animations:{
self.logoImage.layoutIfNeeded()
}, completion: { (finished: Bool) -> Void in
self.logoImage.setNeedsLayout()
self.imageHeightConstraint.constant = 220.0
self.imageWidthConstraint.constant = 220.0
UIView.animate(withDuration: 2.0,
delay:0.0,
options: .curveEaseIn,
animations: {
self.logoImage.layoutIfNeeded()
})
})
}

High CPU Usage because of UIView.animate and UIView.animateKeyframes

I have two view controllers. AnimationVC has some UIView animations, and DestinationVC has none.
I have a CPU usage problem. After I perform the segue, the animation blocks still show up in the Instruments, even though these lines belong to the AnimationVC that performs the segue.
UIView.animate(withDuration: 1.0, delay: 0.0, options: [.curveEaseInOut, .autoreverse, .repeat], animations: {
self.s1.alpha = 0.0
self.s3.alpha = 0.0
}, completion: nil)
and
let dur = 0.5/12
UIView.animateKeyframes(withDuration: 30.0, delay: 0.0, options: [.repeat, .calculationModeCubic], animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: dur, animations: {
self.sc.alpha = 1.0
})
UIView.addKeyframe(withRelativeStartTime: 1.0-dur, relativeDuration: dur, animations: {
self.sc.alpha = 0.0
})
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
self.sc.transform = CGAffineTransform(rotationAngle: .pi*0.2)
})
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
self.sc.center.y = 0.1*self.frame.size.height
})
}, completion: nil)
I tried calling this destruct function...
func destruct(){
layer.removeAllAnimations()
subviews.forEach { $0.removeFromSuperview() }
}
...in
just before performing the segue
in the AnimationVC's deinit method
Still, it shows alive and hogs the CPU with 40% load. How can I destruct this?
I even reset the navigation stack on the DestinationVC with...
self.navigationController?.viewControllers = [self]
...and I see the lines of deinit from AnimationVC, the animation delay closure is still alive.
As it turns out
...
}) { (finished) in
if finished {
self.specialAniamtion(delay: 2.0)
}
}
and calling destruct() on deinit fixed it.
func destruct(){
layer.removeAllAnimations()
}

Swift 1.2 is broken when using constant value within nested blocks

I made a bouncing animation (with some wisdom here to prevent flickering) with the following UIView animation block:
UIView.animateWithDuration(0.3, delay: 0.0,
options: .Repeat | .Autoreverse | .CurveEaseInOut,
animations: {
UIView.setAnimationRepeatCount(1.5)
cellToAnimate?.layer.position.y -= 25.0
}) { (finished) in
UIView.animateWithDuration(0.3, delay: 0.0,
options: .CurveEaseInOut,
animations: {
cellToAnimate?.layer.position.y += 25.0
}, completion: nil)
}
This worked perfectly fine, but then when I abstracted out the constant '25.0' from the two blocks like so:
let yDisplacement = 25.0
UIView.animateWithDuration(0.3, delay: 0.0,
options: .Repeat | .Autoreverse | .CurveEaseInOut,
animations: {
UIView.setAnimationRepeatCount(1.5)
cellToAnimate?.layer.position.y -= yDisplacement
}) { (finished) in
UIView.animateWithDuration(0.3, delay: 0.0,
options: .CurveEaseInOut,
animations: {
cellToAnimate?.layer.position.y += yDisplacement
}, completion: nil)
}
... the Swift compiler started to complain:
Could not find member 'Repeat'.
I couldn't for the life of me figure out why this was happening, until I realised via binary chop that the problem was the constant.
Anybody know why this happens? Or whether this is fixed in Swift 2.0?
When upgrading this code to Swift 2.0 the error also points to .Repeat but states:
Type of expression is ambiguous without more context.
I managed to fix it by being explicit with the yDisplacement type:
let yDisplacement: CGFloat = 25.0
As you cannot use the -= or += operators on CGFloat and Double operands.
This error seems terribly misleading as it is highlighting completely the wrong part of code.
Final code:
let yDisplacement: CGFloat = 25.0
UIView.animateWithDuration(0.3, delay: 0.0,
options: [.Repeat, .Autoreverse, .CurveEaseInOut], // Swift 2.0, use .Repeat | .Autoreverse | .CurveEaseInOut in Swift 1.2
animations: {
UIView.setAnimationRepeatCount(1.5)
cellToAnimate?.layer.position.y -= yDisplacement
}) { (finished) in
UIView.animateWithDuration(0.3, delay: 0.0,
options: .CurveEaseInOut,
animations: {
cellToAnimate?.layer.position.y += yDisplacement
}, completion: nil)
}
The problem is that type of yDisplacement is defined as Double, but you cant mix types in arithmetic operations. In your case you want to subtract it from CGFloat position.y.
Just define type explicitly:
let yDisplacement: CGFloat = 25.0

Resources