I am working with Core Animation using CATransaction. I am using setCompletionBlock in order to capture when the animation is complete so that I can do stuff with the data in the view controller, but I want the animation to be interruptible. Eg. when I call
[self.layer removeAllAnimations]
the animation should stop but the setCompletionBlock should also KNOW if the animation succeeded or failed.
With UIView animation, this is possible since there is a finished variable passed in the completion block and with CAAnimationGroup this is also possible with a finished variable passed to the delegate. How do I accomplish the same with a CATransaction?
Using key-value coding, you can pass any variable you like into the current transaction where it can be picked up by the completion block later. CATransaction, CAAnimation, CALayer, they all accept arbitrary key-value pairs which you can create and use to your heart's content.
https://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CATransaction_class/Introduction/Introduction.html#//apple_ref/occ/clm/CATransaction/setValue:forKey:
Related
In UIViewPropertyAnimator, is there a way to just stop all UIViewPropertyAnimator animations?
Or perhaps simply get all current animations - then of course you could stop them all.
Can this be done?
Or do you really have to
(a) do only one per UIViewPropertyAnimator,
and,
(b) keep a reference to each of those?
Every animation has to have atleast one UIViewPropertyAnimator instance. In order to stop the animation, we have to explicitly call stopAnimation(_:) on the animator instance.
A way would be to make a factory class to fetch UIViewPropertyAnimator instance and keep track of it in a set or array. And then use this factory class to stop or start all the animations at once. Or use one UIViewPropertyAnimator to perform all your animations and stop it.
Using Swift , I animate multiple images with :
cp.animationImages = images
cp.animationDuration = TimeInterval(speed)
cp.animationRepeatCount=count
cp.startAnimating()
I use all sorts of delays to wait between them, but when I need to run a sequence of animations, I would like to have a delegate so each call will be finished with a certain tag, so I can then decide what to do.
I could not find how to use a block/delegate in Swift for this animation.
UIImageView does not support animation completion handlers, but there are extensions available:
https://github.com/gurmundi7/UIImageView-AnimationCompletionBlock
UIProgressView has this setProgress:animated: API.
Is there a way to know exactly when the animation stops?
I mean something like this?
[myProgress setProgress:0.8f animated:YES onCompletion...]
I would like to start fading the progress out, as soon as its animation ends.
From: https://stackoverflow.com/a/16368679/74815
When you are not the author of the animation, you can get a callback when the animation ends by using a transaction completion block:
[CATransaction setCompletionBlock:^{
// doSomethingElse
}];
// doSomething
From the Apple documentation:
Discussion
The completion block object that is guaranteed to be called (on the main thread) as soon as all animations subsequently added by this transaction group have completed (or have been removed.) If no animations are added before the current transaction group is committed (or the completion block is set to a different value,) the block will be invoked immediately.
when I call the runAction:completion:? function of a SKSpriteNode, and pass in a SKAction runBlock action the call back routine never gets called.
Well, this is possibly because SpriteKit has no way of knowing when your block actually stopped affecting the node in question. If the API was better designed maybe it'd give you a way of calling the completion from your block, but it doesn't. However, you can call whatever you'd call in the completion block yourself within your block.
Edit: Yes, the called (in this case SpriteKit) does know when your block ends executing, but your block may perform deferred calls that will further affect the node in question, so it can't be certain the action really ended. For example, think of a block that triggers a timer that varies a certain property over time.
In iOS, you can animate view objects using animation blocks:
[UIView animateWithDuration:1.0 animations:^{
firstView.alpha = 0.0;
secondView.alpha = 1.0;
}];
What we have here is a code block that describes what the view properties will end up looking after the animation is finished.
How does this work?
I could understand (I think) if this was done using some declarative format, but from the looks of it, the animation block is just a regular piece of code that presumably has to be executed, the results inspected and then someone transcoded into the actual lower-level graphics code that performs the animation.
Is the block actually executed (or somehow reverse-engineered) and if so, when?
If this code is executed before the animation starts, then how come the changes to the referenced view properties are not reflected immediately?
What happens if I put code in the block that does not change view properties, but does something else?
Yes, the block is actually invoked -- then it changes the view's properties immediately. The UIView's property setters are responsible to see if the set was used within an animation context -- if so, they calculate the animation frames etc. using CoreAnimation and CoreGraphics.
If you put non-animation code into these blocks, nothing special will happen -- the block will be executed immediately.
It is instructive to look at the equivalent code prior to blocks:
[UIView beginAnimations:#"foo" context:NULL];
[UIView setAnimationDuration:1.0];
firstView.alpha = 0.0;
secondView.alpha = 1.0;
[UIView commitAnimations];
So you see, even before blocks, the properties to change are also set directly; however, they do not take effect immediately (they are animated).
How does it work? Presumably when you set a property on the view, it checks to see if you're run beginAnimations but not commitAnimations, and does not take effect immediately if it is (but rather adds it to the list of things to animate for that animation).
So what the blocks version does is very simple in the context of the pre-blocks version: you can just think of it as running the animation block inside beginAnimations and commitAnimations lines.
Apple doesn't really talk about the nitty-gritty details of how it works, but here's what I think happens:
The system adds KVO observers on all the animatable properties of a view when the view is added to the view hierarchy.
When your animation block executes, the system sets a state that watches for KVO notifications on those properties. The code that gets invoked then creates and adds the appropriate CAAnimation objects to each affected view's layer.