how to know when a coreanimation animation ends - animation

I'm doing some animations with core animation, but I can't found a way to know with a notification or event when the animation block has finish, like in UIVIew animation block you have
setAnimationDidStopSelector:
how can I know this in core animation, thanks for any help

If you are using a CAAnimation instance, look at the animationDidStop:finished: for its delegate.
CAAnimation * animation = [CAAnimation animation];
animation.delegate = yourDelegate; // could be self, for example.
[yourLayer setAnimation:animation forKey:nil];
In the example above, yourDelegate should implement the animationDidStop:finished: method to be able to detect the animation end.

Related

popViewControllerAnimated: custom transition animation?

Yes, I have looked for an answer already. None of the solutions work, except one that doesn't give the option for a fade transition, only flip or curl.
Like this:
methodname
configure animation
[self.navigationController popViewControllerAnimated:NO];
No matter what variety of transition animation config I try, nothing is visibly different from only using the typical single-line pop. If I change it to …Animated:YES];, I get the standard pop animation, maybe with something weird happening from the broken config.
So my question is this: How can I do a pop with, if not CrossDissolve, then at least something that looks the same? Is that even possible with a navigation controller?
Using modal views would have the default animation I want, and I could manage the view stack easily enough, but I don't want to do that.
For this type of transition I would really recommend a modal view controller, thats the way the system was designed.
But if you insist on using the navigation controller there is a way, though somewhat ugly.
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
CATransition *transition = [CATransition animation];
[transition setType:kCATransitionFade];
[self.navigationController.view.layer addAnimation:transition forKey:#"someAnimation"];
[self.navigationController popViewControllerAnimated:YES];
[CATransaction commit];
The CATransaction will disable all standard animations. The CATransition adds a fade transition to the navigation controller layer when views are swapped (in this case removing the viewcontroller view that is popped).
In iOS 7 above, you may want to look into UIViewControllerAnimatedTransitioning for presented view controllers, or UINavigationControllerDelegate method :
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
I have some sample code from another question for more info.
Joris Kluivers's answer in Swift 3 :
CATransaction.begin()
CATransaction.setDisableActions(true)
let animation = CATransition()
animation.type = kCATransitionFade
self.navigationController?.view.layer.add(animation, forKey: "someAnimation")
_ = self.navigationController?.popViewController(animated: false)
CATransaction.commit()

Slow down or pause NSAnimationContext

I have an NSAnimationContext (just a scrolling view) that I would like to slow down and/or pause whenever the cursor enters the view. I have already implemented the detection for when this happens - now I just need to figure out how to slow down the animation that is already in process. I have figured out how to do this with CALayers - but I need to use the animator proxy unable to use several AppKit views within this animation so Core Animation will not work. Does anyone know how to do this? Is there a way to keep track of NSAnimationContexts and then change them later on?
Here is a subsection of my code, The first block is cyclicly called. Everytime one agnation completes the next will begin.
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
context.duration = pixels/speed;
[[currentTweetView animator] setFrame:endRect];
} completionHandler:^{
[currentTweetView removeFromSuperview];
currentTweetView = nil;
[self nextAnimationWithAnimationIndex:currentIndex];
}];
Here is the code in the mouseEntered: method. Whenever this is called, neither completionHandler is ever called and the app freezes.
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
[[[self.subviews objectAtIndex:0] animator] setFrame:finalRect];
context.duration = 100.0;
} completionHandler:^{
NSLog(#"done");
}];
Also, is there any way to end an NSAnimationContext early and not call the completion handler?
I think if you just set the property via the animator proxy again, under a different NSAnimationContext, it will replace the animation that was in progress. This would be analogous to retargeting the animation (e.g. to a new destination).

NSAnimation looping

I've a view that starts an animation when the user drag files on it. The animation shows the files' relative icon (inside an NSImageView Ivar of the NSAnimation custom class) going bigger while fading.
If I loop the animation inside a standard loop like:
CustomAnimation *animation = [[CustomAnimation alloc] initWithDuration: 2.0 animationCurve: NSAnimationLinear]
NSimage *icon;
for (NSString *filename in filenames) {
icon = [[NSWorkspace sharedWorkspace] iconForFile: filename];
NSImageView *myImageView = [[NSImageView alloc] initWithFrame: theFrame];
[myImageView setImage: icon];
[animation setImageView: myImageView];
[animation startAnimation];
}
The loop is too fast and the animations looks like if it were fired almost together (obviously).
What do you think is the best approach to loop an animation several times controlling the delay between the start of one animation and the subsequent?
The reason why your animation blaze by (except perhaps the last one) is that at each iteration your are "overwriting" the previous animation with a new one.
This post on chaining core animations together should do the trick if the idea is to have each animation take the full 2s. You can event add gaps between the animations.
-- Edit --
#Richard that's my mistake, I've misread the question.
A look at the documentaton for NSAnimation suggests that you might use startWhenAnimation:reachesProgress: to chain your animations though.
You can use NSTimer for that purposes.

Animate Frame Size in Cocoa plus notification on animation end

At the moment i have this code:
[[myView animator] setFrameSize:NSMakeSize(300, 150)];
And at the end of the animation i need to launch other operations so i need to know about that.
On the otherside i read the the CAAnimation class has a delegate method that could be exactly what i'm looking for (animationDidStop:finished:), but i like to know it i can have the same effect using animator proxy o CABasicAnimation.

UIImageView/AVAudioPlayer synchronization

I have an UIView that possess an UIImageView as a subview. This image view is intended to display an animation (basically, with the startAnimating method). When the animation start, I also need to play a sound. For this purpose, I use AVAudioPlayer's prepareToPlay and play methods.
Problem I encounter is that the FIRST TIME the global animation (image animation itself + sound) is launched, the sound is systematically played before the image animation is actually started. Not weird at all considering there is no synchronisation whatsoever.
But how could this synchronization be achieved? Is there some sort of callback which could be used know when the image animation is playing and launch the sound play from there...
Or maybe coupling UIImageView and AVAudioPlayer is not a good idea at all?
Here is my current implementation :
- (void)playSample {
previewView_ = [[[PreviewView alloc] initWithFrame:topView.bounds
backgroundImages:backgroundAnimationImages
characterImages:characterAnimationImages] autorelease];
[previewView_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[topView addSubview:previewView_];
[audioPlayer_ setDelegate:self];
[audioPlayer_ setVolume:1.0];
[previewView_ startPreview]; // This calls startAnimating on the UIImageView of previewView_
[audioPlayer_ playSound];
}
Maybe you could use:
[audioPlayer playAtTime:[audioPlayer
deviceCurrentTime] + someDelayTimeInterval]
I found the the audioPlayer (or prepareToPlay) was messing up with my display updates, so what I ended up doing was to create the audioPlayer for each sound in viewDidLoad: and play it in a method called in a background thread:
[self performSelectorInBackground:#selector(playAudioPlayer:)
withObject:self.audioPlayer];

Resources