Cocoa Animation not triggering when called by button - ios

I'm developing an iOS app and i've been asked to add animations to make it more user friendly.
So i want to animate a badge on my button displaying quantity. When the quantity changes, my function valueForItemChanged is called, then i change the value in the bimButtonBadge label and i use a animation which makes its size bounce.
But I'm facing a problem: when i call .animateWithDuration() from an event triggered by a button, it doesn't work:
#IBAction func valueForItemChanged(sender: AnyObject) {
print("value changed");
self.bimButtonBadge.text = String(self.getTotalItemQuantity())
self.bimButtonBadge.transform = CGAffineTransformMakeScale(0.2, 0.2)
UIView.animateWithDuration(1.0,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 4.0,
options: UIViewAnimationOptions.AllowUserInteraction,
animations: {
self.bimButtonBadge.transform = CGAffineTransformIdentity
}, completion: nil)
}
So i tried to make this animation in viewDidLayoutSubviews(), just to see. It worked.
I think viewDidLayoutSubview is called from the main thread so i tried this :
#IBAction func valueForItemChanged(sender: AnyObject) {
print("value changed");
self.bimButtonBadge.text = String(self.getTotalItemQuantity())
self.bimButtonBadge.transform = CGAffineTransformMakeScale(0.2, 0.2)
dispatch_async(dispatch_get_main_queue(), {
UIView.animateWithDuration(1.0,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 4.0,
options: UIViewAnimationOptions.AllowUserInteraction,
animations: {
self.bimButtonBadge.transform = CGAffineTransformIdentity
}, completion: nil)
});
}
Aaaaaand, it worked, partially. Sometimes the label disappears. I searched on the web, but i couldn't find anything related to this. So i'm wondering where i'm wrong.
If anyone could answer me it would be really appreciated.
Thanks

Your animation (both versions) sets the badge's transform to the identity transform, but you don't show any code that sets the transform to anything other than the identity transform. An animation animates a change in a property. If you don't actually change anything, it won't animate.
What are you trying to do? You say you're using a bounce animation, but what do you mean? Bouncing the size? The position?

Problem solved.
I solved this by doing my first transformation in the main thread thanks to Duncan C.
My code is now :
#IBAction func valueForItemChanged(sender: AnyObject) {
print("value changed");
dispatch_async(dispatch_get_main_queue(), {
self.bimButtonBadge.text = String(self.getTotalItemQuantity())
self.bimButtonBadge.transform = CGAffineTransformMakeScale(0.2, 0.2)
UIView.animateWithDuration(1.0,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 4.0,
options: UIViewAnimationOptions.AllowUserInteraction,
animations: {
self.bimButtonBadge.transform = CGAffineTransformIdentity
}, completion: nil)
});
}

Related

UIView Animation Options Repeat count

I'm having some issue with my Swift code, I'm trying to make an UIImageView object fade away and reappear once, but having some issues with having the animation to play only once.
#IBOutlet weak var ball: UIImageView!
#IBAction func onFadeClick(_ sender: Any) {
UIView.animate(withDuration: 1, delay: 0.0, options: [.repeat, .autoreverse], animations: {
self.ball.alpha = 0.0
}, completion: nil)
}
I have attempted to read the documentation and previous questions but all have mentioned to use setAnimationRepeatCount, but xcode has an error stating that it is depreciated in iOS13 (which also does not work). Is there any built in functions I could use to stop the animation after it playing once? I have read somewhere saying using a callback function and reinitialize the animation but I am not exactly sure how to do that. Or is it a better idea to use UIViewPropertyAnimator instead of UIView.animate?
I'm just starting to learn Swift, any help or guidance is appreciated!
You can use the following to achieve your goal :
UIView.animateKeyframes(withDuration: 2, delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
self.ball.alpha = 0.0
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.ball.alpha = 1
}
}) { (isFinished) in
}
Swift 5.x
The current iOS syntax replacement for deprecated approach could be writed like the example below:
UIView.animate(withDuration:1,
delay: 0.5,
options: [.curveEaseInOut, .autoreverse, .repeat]) {
UIView.modifyAnimations(withRepeatCount: 3, autoreverses: true) {
print("repeated stuff")
}
} completion: { _ in
print("done")
}
The iOS 13 replacement for the deprecated approach is https://developer.apple.com/documentation/uikit/uiview/3043564-modifyanimations. Example:
UIView.animate(withDuration:1, animations: {
UIView.modifyAnimations(withRepeatCount: 3, autoreverses: true, animations: {
// whatever
})
})
However, the deprecated approach does still work; it is just deprecated.
instead of the last }) use:
}, completion: { finished in
self.alpha = 1
})

Repeating and reversing an animation multiple times using UIViewPropertyAnimator

I am trying to have my animation ease the screen from black to white to black again and repeat that a certain amount of times. Currently with the code I have the animation eases from black to white then jumps back to black. Is there anyway to run an animation in reverse or add an animation that runs after the first animation is completed?
override func viewDidAppear(_ animated: Bool) {
let viewColorAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator.runningPropertyAnimator(
withDuration: 4.0,
delay: 0.0,
options: [.curveEaseInOut],
animations: {
UIView.setAnimationRepeatCount(3);
self.lightView.backgroundColor = .white
})
viewColorAnimator.startAnimation()
}
I tried adding this block of code to the project but the outcome was the same:
viewColorAnimator.addCompletion {_ in
let secondAnimator = UIViewPropertyAnimator(duration: 4.0, curve: .linear) {
self.lightView.backgroundColor = .black
}
secondAnimator.startAnimation()
}
EDIT: I've found out it is because of the setAnimationRepeatCount because the last of the iterations works properly. How do I run the animation multiple times without the repeat count?
Documentation says that the options related to direction are ignored. you can check the image attached here.
To achieve reverse animation:
Create an animator property.
private var animator: UIViewPropertyAnimator = {
let propertyAnimator = UIViewPropertyAnimator.runningPropertyAnimator(
withDuration: 4.0,
delay: 0.0,
options: [.curveEaseInOut, .autoreverse],
animations: {
UIView.setAnimationRepeatCount(3)
UIView.setAnimationRepeatAutoreverses(true)
self.lightView.backgroundColor = .white
})
return propertyAnimator
}()
P.S. we need to mention the .autoreverse in the options. Otherwise UIView.setAnimationRepeatAutoreverses(true) won't work.
There's an easy way to run animations. And for this method: if you want the animation to repeat after completing, you can add the .autoreverse, and the .repeat option. Like this:
UIView.animate(withDuration: TimeInterval(randomTime), delay: 0, options: [.repeat,.autoreverse], animations: {
//Animation code here
}, completion: {(bool)
//Do something after completion
})
You can put the codes you want to execute after the animation in the completion block.
And, you can use a Timer as a way to run the animation for certain times.
Xcode 9.4.1 (Swift 4.1.2) and Xcode 10 beta 3 (Swift 4.2):
Here's the way to do it using UIViewPropertyAnimator -- basically, we just add .repeat and .autoreverse to the options. You were 99% of the way there:
override func viewDidAppear(_ animated: Bool) {
let viewColorAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator.runningPropertyAnimator(
withDuration: 4.0,
delay: 0.0,
options: [.curveEaseInOut, .repeat, .autoreverse],
animations: {
UIView.setAnimationRepeatCount(3)
self.lightView.backgroundColor = .white
})
viewColorAnimator.startAnimation()
}

How to remove google map marker with fade out animation iOS swift 3?

I am trying to remove my google map marker with fade out animation. And I have tried
CATransaction.begin()
CATransaction.setAnimationDuration(1.0)
myMarker.marker?.map = nil
CATransaction.commit()
CATransaction worked for myMarker.marker?.rotation but not working for fade out animation. What should I do now?
Try like this to hide it with animation, use any method of your choice in option parameter:
UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseOut, animations: {
self.myMarker.opacity = 0.0
}, completion: { (true) in
self.myMarker.map = nil
})
When there are several markers or some code snippet depend on that marker, and you need to remove them synchronously then the process you should be done in background thread. But the background thread can't update the UI.
So, the UI update portion you need do in main thread. Like I have done here,
//Swift 3.1
DispatchQueue.global(qos: .background).async {
//HERE MAY HAVE SOME DEPENDENT CODE
DispatchQueue.main.async {
UIView.animate(withDuration: 0.5, animations: {
self.myMarker.marker?.opacity = 0.0
}, completion: { (yes) in
self.myMarker.marker?.map = nil
})
}
//HERE MAY HAVE SOME DEPENDENT CODE
}

iOS: springWithDamping like animation for KeyFrame animation

I had the following custom transition using UIView.animateWithDuration(...usingSpringWithDamping:...) which worked perfectly.
UIView.animateWithDuration(self.transitionDuration(transitionContext),
delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1.0,
options: nil, animations: {() in
// ...
}, completion: {(Bool) in
// ...
})
But then I had to extend my custom transition with UIViewControllerInteractiveTransitioning in order to have an interactive transition where the user can swipe down the modal view again.
Therefore I needed keyframes for the animation in order that the UIPercentDrivenInteractiveTransition works properly.
So I changed the animation function to use UIView.animateWithKeyframes....
UIView.animateKeyframesWithDuration(self.transitionDuration(transitionContext),
delay: 0.0, options: UIViewKeyframeAnimationOptions.CalculationModeCubic,
animations: {() in
// ...
}, completion: {(Bool) in
// ...
})
My problem now: I lost the spring animation.
I've checked several links, one of the most promising was:
Stackoverflow #1
... but with .addKeyframes... method I cannot specify a completion block that I need.
Any suggestions? :-/

Swift animateWithDuration Completion Runs When Modal View is Pushed?

The following code animates one of my views and has a completion block
UIView.animateWithDuration(0.5, delay: timeToShow, usingSpringWithDamping: 0.75, initialSpringVelocity: 2, options: nil, animations: {
self.murmurComposeTextView.frame = oldFrame
self.showNewMurmurView.frame = self.getLeavingBGFrame()
}, completion: { finished in
self.pickerButtonBig.enabled = true
self.pickerButton.enabled = true
self.isShowingNewMurmur = false
self.murmurComposeTextView.becomeFirstResponder()
})
If I present a modal view while this is running, then quickly dismiss it, I notice 2 things:
The animated hasn't completed, but proceeds as usual (which I want).
The completion block has already run, as pickerButton is enabled, self.murmurComposeTextView.becomeFirstResponder has run, etc. This is what I don't want.
Does anyone know if this behaviour is on purpose, or if I have a bug, and if there's anyway to fix it? Thank you!
The "finished" Bool that is passed into the completion block indicates whether or not the animation was actually completed when the completion block is called.
So you can check that Bool to determine what you want to do. Something like:
UIView.animateWithDuration(0.5, delay: timeToShow, usingSpringWithDamping: 0.75, initialSpringVelocity: 2, options: nil, animations: {
self.murmurComposeTextView.frame = oldFrame
self.showNewMurmurView.frame = self.getLeavingBGFrame()
}, completion: { finished in
if (finished) {
self.pickerButtonBig.enabled = true
self.pickerButton.enabled = true
self.isShowingNewMurmur = false
self.murmurComposeTextView.becomeFirstResponder()
}
})
The docs:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/clm/UIView/animateWithDuration:animations:completion:

Resources