CAAnimation track progress - cocoa-touch

I've been working recently on some animations and it struck me that there is no delegate method of CAAnimation that updates animation progress. I've tried to use a timer and request a transform from a view being transformed (rotated by z axis) but it always returns the same transform.
Is there any way to get the values being updated by CAAnimation?

If you want the details of the current state of the animation of a layer, query [layer presentationLayer]. You can access the transform property within that object.

Unfortunately, no. However, core animation is time based, so you can always mimic it independently. Also, if you are looking for some discrete precise moments, you can split your animation into a chain and update your state within the animationDidStop callback.

Related

NSView setNeedsDisplay causing a performance hit even when draw rect is commented out

I have a Cocoa app that draws a lot data to the main screen(31000 samples by about 315 channels) so we are being very studious about profiling and getting everything as efficient as possible. I have a window controller that when opened updates it's view every 2 seconds based on the data. I am using an NSTimer and specifying the view update method.
The problem I am having is every time the timer fires the method, the main display hiccups slightly. I thought it would just be a matter of optimizing the drawRect method in the view subclass, but when I could not find any specific area in the draw rect method where the performance was bad, I decided to try commenting out the contents of the drawRect method.
results:
If I comment out the contents of the drawRect method, I will still get a hiccup.
If I comment out the call to [view setNeedsDisply: YES] in the calling method, it resolves the hiccup.
What Ive Tried:
1) I modified the method calls so that when the timer fired I was using performSelectorOnMainThread to call the view
2) I then tried to use the main dispatch queue with async.
neither of these things worked.
There is some kind of lag happening here even when there is no drawing work to do.
Any help is appreciated.

How to check if SpriteBuilder timeline is done running in code

so first I am running an animation.
[self.animationManager runAnimationsForSequenceNamed:#"calibrateButtonOut"];
If I want to run an animation when that animation has ended, what do I write? I can't find a method that is equal to isDone.
The CCBAnimationManager provides two ways to get informed about animations that completed.
Using the setCompletedAnimationCallbackBlock: method. This way the provided block will be exectued for every completed timeline animation. To check the name of the timeline animation that just completed a develeoper can use the lastCompletedSequenceName method.
Implementing the CCBAnimationManagerDelegate protocol and setting a class up as the delegate of the CCBAnimationManager. This way the CCBAnimationManager will call completedAnimationSequenceNamed: for each completed timeline animation.

Animation and MVC principle

I always design my programs according to MVC principle, but fitting animation in is pain-in-the-ass.
I have implemented following scheme so far:
1) Model does number of actions [] and sends notifications to all listeners;
2) Upon reciving a notification View adds an animation to the queue.
It's workable approach, but it has one huge drawback — model and UI become unsyncronized. For example there are 10 actions already applied to the model, but UI is still in state, where 5 of them are applied.
This drawback forces animations to be coded uninterruptable, which is not good practice for UI design. Please, suggest how to resolve the issue.
You could update your model after the animation finished. This way, your animations are a representation that the user can use to determine when an actions is finished. E.g. after dragging an object to its destination, the object remains (model-side) on its old location until the animation finishes, only then is it moved to the new one.
That way, if the animation fails because the user interrupts it or an error ocurrs, your model will still be synchronized with the current state of your view.

Detecting collision, during a CAKeyFrameAnimation

Is it possible to detect the collision of two UIImageViews while one is travelling along a path during a CAKeyFrameAnimation?
If so how is this done, I have tried multiple methods including checking both the CGRects for collision during the animation - but can't find a suitable method for performing a method during a CAKeyFrameAnimation and trying to detect collision of the path and the UIImageView.
You need to get the properties from the presentation layer. It will have the best approximation of information that exists during animation. Access it by
view.layer.presentationLayer
Look at the documentation for CALayer/presentationLayer for more details.
When you want to check for collisions, you would grab the presentationLayer of each object, then access whatever properties you want to test for collision. The exact way to check would depend on which type of layer, and whether you wanted simple hitTest-ing or depth checking. Only you know when and what type of collisions you want to look for.
However, to access the properties of an object while it is animating, you need the presentationLayer.
EDIT
You can make these check whenever you want. You can do it in the context of another action, or with an NSTimer to do it at some interval. You can even use CADisplayLink, which while hook you into the animation timer itself.
If you use CADisplayLink, I suggest setting frameInterval at the highest value possible, and still do what you want, so as to not impact performance.
timer = [CADisplayLink displayLinkWithTarget:self selector:#selector(checkForCollisions)];
// Callback is for every frame, which is 60 times per second.
// Only callback every 6 frames (which is ten times per second)
timer.frameInterval = 6;
[timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Don't forget to invalidate the timer when you are done.

CABasicAnimation and custom types

I'm not very familiar with CoreAnimation, so I hope I've just missed something pretty simple. I want to animate a custom property (NSGradient) of a NSView in a simple manner, with [[view animator] setGradient:gradient];. I defined + (id)defaultAnimationForKey:(NSString *)key and returned a simple CABasicAnimation, however, no animation is executed. Since this works for simpler types and NSColor, I guess CABasicAnimation doesn't work with gradients. Fine, but in this particular case gradients are trivial (two stops, always), so I can easily write an interpolation functions. The question: how can I define a custom interpolation? I googled around regarding delegates on view, layer and animations, subclassing animation class etc., but I wasn't able to figure the things out. Thanks!
I thought I remembered passing by some Apple documentation when I was learning how to use Core Animation that showed how to set up animations that couldn't be handled by properticode describedes that are supplied with defined animations. Along the way I stumbled across some sample code from Apple that is described as:
A single gradient layer is displayed and continuously animated using new random colors.
That may be the answer to the specific task you already handled another way. I found it in the Documentation and API Reference within Xcode and the name of the sample code is simply Gradients. (Note that there is an original version 1.0 and an updated version 1.1 that was redone this year in April and so should be easier to use with current tools.
But, the larger question of creating a custom animation that can't be automated by Core Animation itself is to follow the example from Apple's Animation Programming Guide for Cocoa in the section Using an NSAnimation Object. It's described under the topic Subclassing NSAnimation and the recommended method is shown under the heading Smooth Animations. You override the setCurrentProgress: method so that each time it is called you first invoke Super so that NSAnimation updates the progress value, i.e., your custom animated property and then do any updating or drawing needed for the next frame of your animation. Here are the notes and example code provided by Apple in the referenced documentation:
As mentioned in “Setting and Handling Progress Marks,” you can attach a series of progress marks to an NSAnimation object and have the delegate implement the animation:didReachProgressMark: method to redraw an object at each progress mark. However, this is not the best way to animate an object. Unless you set a large number of progress marks (30 per second or more), the animation is probably going to appear jerky.
A better approach is to subclass NSAnimation and override the setCurrentProgress: method, as illustrated in Listing 4. The NSAnimation object invokes this method after each frame to change the progress value. By intercepting this message, you can perform any redrawing or updating you need for that frame. If you do override this method, be sure to invoke the implementation of super so that it can update the current progress.
Listing 4 Overriding the setCurrentProgress: method
- (void)setCurrentProgress:(NSAnimationProgress)progress
{
// Call super to update the progress value.
[super setCurrentProgress:progress];
// Update the window position.
NSRect theWinFrame = [[NSApp mainWindow] frame];
NSRect theScreenFrame = [[NSScreen mainScreen] visibleFrame];
theWinFrame.origin.x = progress *
(theScreenFrame.size.width - theWinFrame.size.width);
[[NSApp mainWindow] setFrame:theWinFrame display:YES animate:YES];
}
So basically you define a "progress value" (possibly composed of several values) that defines the state of your custom animation and write code that given the current "progress value" draws or changes what is drawn when the animation is at that particular state. Then you let NSAnimation run the animation using the normal methods of setting up an animation and it will execute your code to draw each frame of the animation at the appropriate time.
I hope that answers what you wanted to know. I doubt I could have found this easily by searching without having seen it before since I finally had to go to where I thought it might be and skim page by page through the entire topic to find it again!