How to create complex animation with better performance in iOS? - ios

All the animations mean change of layer.transform or frame properties. There are 2 main questions about performance:
I have multiple views which I should animate simultaneously. What is better: to create multiple animateWithDuration blocks or to create one such block and iterate views in it?
My animation requires complex calculations and I need to call animateWithDuration enough often. Should I perform all the calculations before the animation block or is there no difference for performance?

Nobody has answered yet. So let I answer my own question and you will correct it if I'm mistaken.
I recommend one block only. The usual animateWithDuration:animations: doesn't support simultaneous animations properly (at least in my case it caused some troubles). I suggest to use RZViewActions instead - it uses more complex approach with dispatch_group_t for simultaneous animations (and actions in general). In the last version you don't even need to prepare groups/sequences before the animation start.
The only difference I see is the code outside animateWithDuration:animations: is performed in the same NSRunLoop cycle and if I place it inside the animation block it will be calculated in the next cycle. So for example, it will be useful to place the calculations outside the block if sometimes you don't want to start the animation according to the results of these calculations.
On the other hand it may slow down the current cycle which is usually more critical than than the slower performance of the next cycle. Additionally you should think about variables you need to pass into the block correctly.
In both cases the animation will not start until the end of the animation block. So if you set some visual variable (for example, view's frame) it is set as usually and you can use it at once. But this value is not rendered until the beginning of the completion block. So you with animateWithDuration:animations: you will see the starting and the ending value only. Even if the animation is interrupted it jumps to the ending value at once (it is default behaviour if you don't specify additional options).

Related

Do animations use juice while the view is hidden?

I have this small view V
v: UICrazyView
which has sundry animations, which run often, and which follow various annoying states and inputs.
Now on top of that, from time to time the whole thing is just hidden
var slideAwaySomePanel: Bool {
didSet {
.. do many other things
v.isHidden = slideAwaySomePanel
}
}
It might be hidden for a minute, an hour, forever, or never.
It occurred to me, while V is hidden ... are the animations still running?
Do they still use a lot of battery/performance?
I was about to override isHidden and start writing a whole lot of fragile PITA code that would know what to do as isHidden is toggled, but maybe that is pointless.
I wish to know
When you isHidden, do all the calculations (and even drawing?) continue for the ongoing animations? Are you still using battery? Should we carefully stop everything during isHidden to save battery / performance. Or, does isHidden stop everything anyway? Or does it still do the timers and curves, but not waste any power on drawing?
Do all the timers and so on actually "pause" when you go in to isHidden? If you have an endless repeating animation, or, a 10 second fade or such, does it "hold" at an exact position, and continue when you not isHidden? Or what happens?
In short should we carefully and tediously stop by-hand animations, when isHidden is in effect? Or is there no point?
(It occurs to me, this is very much like in cg where you either do or don't have animations or other physics ongoing when objects are occluded or out of the frustrum. For this reason game engines simply have a toggle to decide on exactly that behavior "keep going or not when I'm offscreen?")
I'm pretty sure, even though I have no reference, that hidden views are not animated because Core Animation was implemented very efficiently in terms of performance.
Core animation layers and animations have their own clock. The animation state is calculated from this time. The clock continues to run when the view is not visible. Since neither the layer nor the animation object are destroyed by hiding the view, the animation has exactly the same state after reappearing that it would have had if the view had not been hidden.
Apple gives some nice examples how to modify the animation timing for some use cases.

IOS, Swift, Animation chaining, waiting main thread until chain completes

This question has been asked at least as many times as I've searched for the answer but never to my satisfaction. I have a view with 52 subviews representing a deck of cards. The cards appear in the center of the screen, split into two stacks of cards and then merge together as a shuffled deck.
If I call self.standardShuffle() from viewDidAppear(), after instantiating the card images, it works just fine.
But if I call self.standardShuffle() 2 times in a row, the second call catches the first animation in flight and and the animation is ruined. There has to be a way to block the calling thread until the animation chain completes. Timers get too unwieldy and I can't put all of my code inside animation blocks (and it doesn't work, anyway.)
Anybody have the real answer? Please.
There has to be a way to block the calling thread
No there is not. Never block. Never.
If you think the answers you've seen are not satisfactory, you have not read them carefully. Read them and believe them. You can easily (and in many different ways) arrange to be called back after the first animation; that is the moment to begin the second animation. Or, create a single grouped animation that performs two animations in succession.
Those are your choices — your only choices. If you're finding that difficult to reconcile with your code, it's because you've architected your code incorrectly. Rearchitect it. Use the framework, don't fight it.

CoreAnimation confusion: CATransaction vs CATransition vs CAAnimationGroup?

I've used these three classes several times by separate several times.
For example when I want to group several animations (i.e.: CABasicAnimations, etc) to happen simultaneously I first think of CAAnimationGroup, when I want to see a layer change from one state to another (i.e.: appear, slide in, etc) I think of CATransition.
But at the same time CATransaction is meant to execute animations in batches (WTH?)
CATransaction and CATransition seem to be different beasts but I usually see CATransitionsinside CATransactions? I've read the docs several times but they are never compared side by side and when/what they should be used for.
It would be great if someone could point what is their relationship/usage :)
CATransaction and CATransition are indeed different beasts...
It seems that the missing bit in your understanding is about CATransaction; once you get that, then maybe all the pieces will fall into place by themselves.
A CATransaction is always created every time you have a Core animation going on.
Every modification to a layer is part of a transaction. CATransaction is the Core Animation class responsible for batching multiple layer-tree modifications into atomic updates to the render tree.
(source)
What happens is that if you do not specify one explicitly, then an implicit CATransaction is created for you.
You can create an explicit transaction (by means of [CATransaction begin/commit]) to tune several parameters of an animation, like whether default animations should be used, how long they are etc. Those are all described in CATransaction reference.
Explicit transactions are particularly useful when setting the properties of many layers at the same time (for example, while laying out multiple layers), temporarily disabling layer actions, or temporarily changing the duration of resulting implied animations.
So, resuming it all, CATransaction is the "big umbrella" under which a core animation animation is run, wether it is a CABasicAnimation, a CATransition, or group animation. It allows you to set some general parameters affecting the way the animation/transition takes place and if you do not provide one, a default (implicit) one is used.
Hope this helps.

iOS class that allows an image to "drift" across screen?

I've seen a lot of helpful tutorials that show one how to:
make an image move according to a predefined path, or
move the image, a few pixels at a time, in response to a UIButton.
What I want to do is have the image "drift" arbitrarily according to an Vxy velocity I define, then have the button(s) change the velocity. (Yes, I'd have it slow down with time if no action made).
In other languages there might have been a way to do Change Pxy position by Vxy (to ad infinitum) unless button pushed. I believe GET was the command. I can think of a way to do that in iOS I suppose but that would involve setting up a series of 1 sec CGMutablePathRef anims. Alternatively, I have seen some talk of NSTimer: would it be a good practice to introduce some sort of delay: draw, delay, draw, delay.
Request: specific classes or terms I can search in the manuals for myself.
Iirc using uiview's animateWithDuration:completion is cheaper than using core animation. frame is an animatable property. So, yeah I think I would use an NSTimer to call your method for default calculation of the end frame of your view and then call animateWithDuration:completion there.
[deleted bad idea]
I ran across a wonderful tutorial for anyone considering such a project;
http://www.youtube.com/watch?v=nH_Rj152DRM
I believe the key "noob" problem I was having was in not realizing I should declare the instance variable for my sprite/ image in the
-(void) viewDidLoad{
then work on other properties of the animation in touches/ other user events. Once I figured that out, I am now capable of doing the heavy lifting for the rest of the project myself.

How to call another method during key frame animation in iOS?

For CAKeyframeAnimation, there are delegates for animation start and animation stop. But I want to call a method in each time frame (to update some subview information on-the-fly). Is there any way I can do it?
I do not believe there is any way to do this. The closest you can come is running a timer with a very short period that queries the currently-visible layer properties by calling -presentationLayer on the layer and querying the result. However this is not guaranteed to match precisely with what's on-screen, as it effectively generates a copy of the model layer with the animations applied to the current time rather than querying the actual presentation layer used internally.

Resources