UIButton animation ignores target selector in Swift - swift

I've added this animation code to the end of a function that is called when the button is pushed, but while the animation is happening, it ignores the set target selector until the animation is finished. The animation is very fast, but I'd like users to be able to press it rapidly.
let transforms: CGAffineTransform = .identity
mirroredButton.transform = transforms
UIView.animate(withDuration: 0.05, animations: {
mirroredButton.transform = transforms.scaledBy(x: 0.75, y: 0.75)
},
completion: { _ in
UIView.animate(withDuration: 0.1) {
mirroredButton.transform = transforms.scaledBy(x: 1.0, y: 1.0)
}
})
Update:
Using the answer, I updated my animation code as shown below. Both animation calls need options. The 2nd has a nil completion handler.
let transforms: CGAffineTransform = .identity
mirroredButton.transform = transforms
UIView.animate(withDuration: 0.05, delay: 0.0, options: .allowUserInteraction, animations: {
mirroredButton.transform = transforms.scaledBy(x: 0.75, y: 0.75)
},
completion: { _ in
UIView.animate(withDuration: 0.1, delay: 0.0, options: .allowUserInteraction, animations: {
mirroredButton.transform = transforms.scaledBy(x: 1.0, y: 1.0)
}, completion:nil)
})

User interaction is disabled for the duration of a view's animation. If it's critical that the user should interact with a view during an animation, you can pass in the option .allowUserInteraction, like so:
UIView.animate(withDuration: 1.0, delay: 0.0, options: .allowUserInteraction, animations: {
//animate here
})

Related

Touch Labels That Keep Animating

I'm having an issue trying to touch a label that keeps animating because during the animation it becomes an image (set the animation on repeat). Is there a way to touch it during animation (I cant't use UITapGestureRecognizer) ?
func animatePro() {
UIView.animate(withDuration: 2, delay: 0, options: [.autoreverse, .repeat], animations: {
//1.5 times it's normal size
self.proLabel.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}){ (finished) in
self.proLabel
.transform = CGAffineTransform.identity
}
}
func animateRev() {
UIView.animate(withDuration: 2, delay: 0, options: [.repeat], animations: {
//1.5 times it's normal size
self.revLabel.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}){ (finished) in
UIView.animate(withDuration: 2, delay: 0, animations: {
self.revLabel.transform = CGAffineTransform.identity
})
}
}
Add allowUserInteraction
options: [.allowUserInteraction,.autoreverse, .repeat]

How to create twitter tab bar push animation

I have the following code:
private var bounceAnimation: CAKeyframeAnimation = {
let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.scale")
bounceAnimation.values = [1.0, 1.4, 0.9, 1.02, 1.0]
bounceAnimation.duration = TimeInterval(0.3)
bounceAnimation.calculationMode = CAAnimationCalculationMode.cubic
return bounceAnimation
}()
This creates the animation where the icon gets bigger and then smaller. I am trying to create the animation where the icon gets smaller and then back to normal like it's being pushed similar to twitter, Spotify, etc. I assume it's just changing around the bounce values all though I'm not sure how would I do this.
I'd use a normal UIView.animate function like this:
UIView.animate(withDuration: 0.05, delay: 0, options: .curveLinear, animations: {
view.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
}, completion: nil)
UIView.animate(withDuration: 0.3, delay: 0.05, usingSpringWithDamping: 0.2, initialSpringVelocity: 7, options: .curveEaseOut, animations: {
view.transform = .identity
}, completion: nil)
Just change view to be whatever view you're trying to animate. Then mess around with the initial scale, the duration and the spring dampening to get the animation you want!

Swift move image from right to left than from left to right

I want to make an animation that move a background image from right to left than left to right.
I use this code but not works
UIView.animate(withDuration: 5, delay: 0, options: .repeat ,animations: { () -> Void in
imageView.transform = CGAffineTransform(translationX: -imageView.frame.width + self.view.bounds.width, y: 0)
UIView.animate(withDuration: 5, delay: 1, options: .repeat ,animations: { () -> Void in
imageView.transform = CGAffineTransform(translationX: +imageView.frame.width - self.view.bounds.width, y: 0)
})
})
I solved with this
UIView.animate(withDuration: 30.0, delay: 0, options: [.repeat, .autoreverse], animations: {
imageView.transform = CGAffineTransform(translationX: -imageView.frame.width + self.view.bounds.width, y: 0)
}, completion: nil)
Use the following code if you want to use the legacy animate(withDuration:animations:) API. However, you need to wait for the first animation to be finished - this means you have to use the completion block.
However, your value for translationX does not makes sense as well.
UIView.animate(withDuration: 1, animations: {
self.imageView.transform = CGAffineTransform(translationX: -self.imageView.frame.width, y: 0)
}) { _ in
UIView.animate(withDuration: 1) {
self.imageView.transform = CGAffineTransform.identity
}
}
I would strongly recommend having a look at the "new" way of doing Animations: UIViewPropertyAnimator(https://developer.apple.com/documentation/uikit/uiviewpropertyanimator)

Swift UIView Animate doesn't work properly

Slide up animation will be triggered when a button is clicked.
func animation_onClick(action: String) {
let up = CGAffineTransform(translationX: 0, y: -30)
myView.transform = CGAffineTransform(translationX: 0, y: 0)
UIView.animate(withDuration: 0.5, delay: 0.0, options: [], animations: {
self.myView.transform = up
}, completion: nil)
}
My code means when the function runs, myView’s position will be set to (0, 0) referring to its original position every time before it was set to (0, -30).
But when I run the app, I repeatedly click the button, somehow myView doesn't go back to its origin, it goes below where it should be. What I mean is it's not supposed to go below its origin.
See the gif below.
Try the following
func animation_onClick(action: String) {
myView.layer.removeAllAnimations()
myView.transform = .identity
UIView.animate(withDuration: 0.5, delay: 0.0, options: [], animations: {
self.myView.transform = CGAffineTransform(translationX: 0, y: -30)
}, completion: nil)
}

Immediate UIButton rotation transform, with animated scale

I would like to animate the scale of a UIButton, and animate the scale again when completed, but have it rotate without animation. I've tried to put the rotation transform in an animation call with no duration, but somehow it still makes it part of or replace the scaling animation.
I extended the animation of the scale by a second to demonstrate the result more clearly.
let transforms: CGAffineTransform = .identity
button.transform = transforms
UIView.animate(withDuration: 1.05, delay: 0.0, options: .allowUserInteraction, animations: {
button.transform = transforms.scaledBy(x: 0.75, y: 0.75)
}, completion: { _ in
button.transform = CGAffineTransform(rotationAngle: 90 * (.pi/180)) // I want this to happen immediately, without animation
UIView.animate(withDuration: 1.1, delay: 0.0, options: .allowUserInteraction, animations: {
button.transform = transforms.scaledBy(x: 1.0, y: 1.0)
}, completion:nil)
})
You set the rotate transform to happen immediately - and it does! But then you immediately start animating it again, with respect to your transforms variable - reverting its current transform to the one in that variable.
Instead of using a variable to keep track of the button's transform, just refer to its current transform, like so:
button.transform = .identity
UIView.animate(withDuration: 1.05, delay: 0.0, options: .allowUserInteraction, animations: {
button.transform = button.transform.scaledBy(x: 0.75, y: 0.75)
}, completion: { _ in
button.transform = CGAffineTransform(rotationAngle: 90 * (.pi/180)) // I want this to happen immediately, without animation
UIView.animate(withDuration: 1.1, delay: 0.0, options: .allowUserInteraction, animations: {
button.transform = button.transform.scaledBy(x: 1.0, y: 1.0)
}, completion:nil)
})