tags:

views:

94

answers:

3

So I have some NSButtons and NSImages (I assume they would be moved the same way) that I want to move. I want to move them to new coordinates on the window. I assume that I could figure out the coordinates I want to move them to on Interface Builder, and then move them programmatically.

Additionally, how can I animate this movement? And control that animation's speed, style, etcetera? Is there a built in function for that? Or do I have to make image files and cycle through them?

NOTE: I primarily want to know how to change the coordinates of the object, the animation thing is secondary, but it would make me very happy if you could describe that as well.

A: 

Each UI element has a bounds and frame property. The frame property has an x,y,width and height attribute. If you want to move an item around, simply adjust the values of the frame property:

NSButton *button // assume this exists as your UI object
NSRect rect = NSMakeRect(50.0, 40.0, 250.0, 100.0);
[button setFrame:rect];

This will move it without any animation. If you want animation, go through the object's animation proxy (good for simple stuff:

[[button animation] setFrame:rect];
darren
I'm assuming animation isn't literally the method that is used, do you have a specific example?
Regan
Oh, ok so it is animator, not animation, awesome.
Regan
sorry, yeah I typed this up without actually compiling it. The idea is that for simple animations you don't need to deal with core animation directly. Instead, yo can ask an NSView (or its subclass) for an animation proxy. The proxy passes through the message you wanted to send, but it allows you to animate it instead of just moving it.
darren
+3  A: 

You may use Core Animation for this: http://www.cocoadev.com/index.pl?CoreAnimation

kovpas
Thanks, that article is great.
Regan
+3  A: 

Update: My original post was about how to animate two rects on an iPhone but that was not what the original poster/question asked. That's what I get for trying to answer SO questions after 24 hours of coding. Anyhoo, I'm going to leave that answer here in case anyone comes along and wants to learn about this on the iPhone. Here is an example to do the exact same thing on a Mac. Note that this example expects you to first setup a sample project in Interface Builder with an NSWindow (any default project should do that):

------ Mac Example:

// MacAnimationExample.h:

#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>

@interface ColorView : NSView {
    NSColor             *backgroundColor;
}

@property( nonatomic, retain ) NSColor      *backgroundColor;

@end


@interface MacAnimationExample : NSObject <NSAnimationDelegate, NSApplicationDelegate> {
    ColorView           *red;
    ColorView           *yellow;

    IBOutlet NSWindow   *window;
}

@property( assign ) IBOutlet NSWindow *window;

@end


// MacAnimationExample.m:

#import "MacAnimationExample.h"

@implementation ColorView

@synthesize backgroundColor;

- (void) setBackgroundColor:(NSColor *) iColor {
    [iColor retain];
    [backgroundColor release];
    backgroundColor = iColor;

    [self setNeedsDisplay: YES];
}

- (void) drawRect:(NSRect) iRect {
    [backgroundColor set];
    NSRectFill( iRect );
}

@end


@implementation MacAnimationExample

@synthesize window;

- (void) animateIt {
    NSAnimation                 *animation;
    NSArray                     *animations;
    NSRect                      redFrame, yellowFrame;
    NSMutableDictionary         *redInfo, *yellowInfo;

    redFrame = [red frame];
    yellowFrame = [yellow frame];

    redInfo = [NSMutableDictionary dictionary];

    [redInfo setObject: red forKey: NSViewAnimationTargetKey];
    [redInfo setObject: [NSValue valueWithRect: redFrame] forKey: NSViewAnimationStartFrameKey];
    [redInfo setObject: [NSValue valueWithRect: yellowFrame] forKey: NSViewAnimationEndFrameKey];

    yellowInfo = [NSMutableDictionary dictionary];

    [yellowInfo setObject: yellow forKey: NSViewAnimationTargetKey];
    [yellowInfo setObject: [NSValue valueWithRect: yellowFrame] forKey: NSViewAnimationStartFrameKey];
    [yellowInfo setObject: [NSValue valueWithRect: redFrame] forKey: NSViewAnimationEndFrameKey];

    animations = [NSArray arrayWithObjects: redInfo, yellowInfo, nil];

    animation = [[[NSViewAnimation alloc] initWithViewAnimations: animations] autorelease];
    [animation setDelegate: self];
    [animation setDuration: 0.5];
    [animation startAnimation];
}

- (void) animationDidEnd:(NSAnimation*) animation {
    [self animateIt];
}

- (void) applicationDidFinishLaunching:(NSNotification *) aNotification {
    NSRect                      bounds;
    NSView                      *contentView;

    contentView = [window contentView];

    bounds = [contentView bounds];
    bounds.size.width = floorf( bounds.size.width * 0.5 );
    red = [[[ColorView alloc] initWithFrame: bounds] autorelease];
    red.backgroundColor = [NSColor redColor];
    [contentView addSubview: red];

    bounds.origin.x += bounds.size.width;
    yellow = [[[ColorView alloc] initWithFrame: bounds] autorelease];
    yellow.backgroundColor = [NSColor yellowColor];
    [contentView addSubview: yellow];

    [self animateIt];
}

@end

------ iPhone Example:

Here's an example that shows how to animate two rects. Once you get this figured out the rest of the simple UIView-based animation is pretty easy. There is lower layer CoreAnimation stuff you can look into and with newer OS's there's an animation block concept that you can look at. This is where you should start though:

@interface ExampleViewController : UIViewController {
    UIView                  *red;
    UIView                  *yellow;
}

@end

@implementation ExampleViewController

- (void) loadView {
    UIView          *background;
    CGRect          frame;

    frame = [UIScreen mainScreen].bounds;

    // background view contains red & yellow subviews
    background = [[[UIView alloc] initWithFrame: frame] autorelease];

    frame.size.width = floorf( frame.size.width * 0.5 );
    red = [[[UIView alloc] initWithFrame: frame] autorelease];
    red.backgroundColor = [UIColor redColor];

    frame.origin.x = frame.size.width;
    yellow = [[[UIView alloc] initWithFrame: frame] autorelease];
    yellow.backgroundColor = [UIColor yellowColor];

    [background addSubview: yellow];
    [background addSubview: red];

    self.view = background; 
}

- (void) viewWillAppear:(BOOL) animated {
    CGRect              temp;

    // normally you will let the animated parameter
    // control whether or not the view animates.  for
    // demonstation I add a hack to force animation to begin:
    animated = YES; // hack

    if ( animated ) {
        [UIView beginAnimations: nil context: nil];
        [UIView setAnimationDelegate: self];
        [UIView setAnimationDidStopSelector: @selector(startAnimation)];
        [UIView setAnimationDuration: 0.5];
    }

    temp = red.frame;
    red.frame = yellow.frame;
    yellow.frame = temp;

    if ( animated ) [UIView commitAnimations];
}

- (void) startAnimation {
    [self viewWillAppear: YES];
}

@end
par
The question is about mac development. Not iPhone.
kovpas
Hmm, true. I've got my NS and my UI confused it seems. I'll go see about writing the same thing for Mac.
par