Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I animate a content switch in an NSImageView?

I want to switch the image shown in an NSImageView, but I want to animate that change. I've tried various methods to do this. Hopefully one of you could suggest one that might actually work. I'm working with Cocoa for Mac.

like image 574
Alexsander Akers Avatar asked May 08 '10 22:05

Alexsander Akers


2 Answers

As far as I know, NSImageView doesn't support animating image changes. However, you can place a second NSImageView on top of the first one and animate hiding the old one and showing the new one. For example:

NSImageView *newImageView = [[NSImageView alloc] initWithFrame: [imageView frame]];
[newImageView setImageFrameStyle: [imageView imageFrameStyle]];
// anything else you need to copy properties from the old image view
// ...or unarchive it from a nib

[newImageView setImage: [NSImage imageNamed: @"NSAdvanced"]];
[[imageView superview] addSubview: newImageView
                       positioned: NSWindowAbove relativeTo: imageView];
[newImageView release];

NSDictionary *fadeIn = [NSDictionary dictionaryWithObjectsAndKeys:
             newImageView, NSViewAnimationTargetKey,
             NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
             nil];
NSDictionary *fadeOut = [NSDictionary dictionaryWithObjectsAndKeys:
             imageView, NSViewAnimationTargetKey,
             NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
             nil];
NSViewAnimation *animation = [[NSViewAnimation alloc] initWithViewAnimations:
              [NSArray arrayWithObjects: fadeOut, fadeIn, nil]];
[animation setAnimationBlockingMode: NSAnimationBlocking];
[animation setDuration: 2.0];
[animation setAnimationCurve: NSAnimationEaseInOut];
[animation startAnimation];
[imageView removeFromSuperview];
imageView = newImageView;
[animation release];

If your view is big and you can require 10.5+, then you could do the same thing with Core Animation, which will be hardware accelerated and use a lot less CPU.

After creating newImageView, do something like:

[newImageView setAlphaValue: 0];
[newImageView setWantsLayer: YES];
// ...
[self performSelector: @selector(animateNewImageView:) withObject: newImageView afterDelay: 0];

- (void)animateNewImageView:(NSImageView *)newImageView;
{
    [NSAnimationContext beginGrouping];
    [[NSAnimationContext currentContext] setDuration: 2];
    [[newImageView animator] setAlphaValue: 1];
    [[imageView animator] setAlphaValue: 0];
    [NSAnimationContext endGrouping];
}

You'll need to modify the above to be abortable, but I'm not going to write all your code for you :-)

like image 129
Nicholas Riley Avatar answered Nov 11 '22 15:11

Nicholas Riley


You could implement your own custom view that uses a Core Animation CALayer to store the image. When you set the contents property of the layer, the image will automatically smoothly animate from the old image to the new one.

like image 20
Rob Keniger Avatar answered Nov 11 '22 15:11

Rob Keniger