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]
Related
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)
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)
}
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
})
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)
})
I'm making a tap game, and this is the button with the animation. It is very slow, and I want to speed it up so when the user taps, it will reset the animation and count the tap.
Currently, it is slow to the point that it will miss taps if tapped again while the animation is still going on.
#IBAction func slimeTap(_ sender: UIButton) {
tapCount += tapIncrease
checkLevel(tapCount)
UIView.animate(withDuration: 0.03, animations: {
//shrink
self.playSound()
sender.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
}, completion: {_ in
//change it back to how it was
//grow
UIView.animate(withDuration: 0.05, animations: {
sender.transform = CGAffineTransform(scaleX: 1, y: 1)
})
})
}
Try adding .layer.removeAllAnimations() to remove any existing animations on the layer, and .allowUserInteraction as an animation option to enable and register user tap events:
#IBAction func slimeTap(_ sender: UIButton) {
tapCount += tapIncrease
checkLevel(tapCount)
resizingView.layer.removeAllAnimations()
UIView.animate(withDuration: 0.3, delay: 0, options: [.allowUserInteraction], animations: {
self.playSound()
sender.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
}) { _ in
UIView.animate(withDuration: 0.5, delay: 0, options: [.allowUserInteraction], animations: {
sender.transform = CGAffineTransform(scaleX: 1, y: 1)
})
}
}