CocoaDev

Edit AllPages

Here’s an example that shows how to spin an object centered about a point in a view.

SpinnerView.h

#import <Cocoa/Cocoa.h>

@interface SpinnerView : NSView { float rad; } @end

SpinnerView.m

#import “SpinnerView.h”

@implementation SpinnerView

}

@end

This code gives you the option to animate the spinning motion of a double headed arrow about an offset point or to simply rotate the double headed arrow about an offset point. The offset point is currently set to the center of the view, but you can easily change this location to any point you wish by changing the line:

NSPoint offset = NSMakePoint(NSMidX(visibleRect), NSMidY(visibleRect));

If you set the “animate” variable to “NO”, you will set the amount the drawing will be rotated to a fixed angle associated with the slope of a vector. The line

else rad = [self slopeInRadiansFromVector:NSMakeSize(1.0f, 1.0f)];

sets the rotation (in radians) to pie over four (i.e. 45 degrees).

–zootbobbalu


Nice code. Puts a new ‘spin’ on an old cursor. But…“pie over four”? That takes the cake. A little half-baked, in other words. Are you completely crustworthy?


LOL!! that’s pretty funny!! Just making sure everyone was paying attention ;-)

–zootbobbalu


Here’s a simple example if the example above is hard to understand

SpinnerView.h

#import <Cocoa/Cocoa.h>

@interface SpinnerView : NSView { float rad; } @end

SpinnerView.m

#import “SpinnerView.h”

@implementation SpinnerView

}

@end

–zootbobbalu


See also QuartzShapeDrawing

Warning: Both above examples use [self performSelector:@selector(display) withObject:nil afterDelay:0.01f];

I don’t think it is strictly correct to perform a method, -display, that does not take an argument but pass an argument anyway.


It’s also a really bad way to do animation. The correct way would be to create an NSTimer to call a method which calls setNeedsDisplay:YES. That way you can do things like easily cancel the animation, change its rate, etc.


From Apple’s documentation on performSelector:withObject:afterDelay: -> * Sends an aSelector message to the receiver sometime after delay. This method returns before the aSelector message is sent. The aSelector method should not have a significant return value and should take a single argument of type id, or no arguments; anArgument will be the argument passed in the message, or nil if the method does not take any arguments. Note that self and anArgument are retained until after the message is sent. See �Selectors� for a description of the SEL type. *

I agree that a timer would be better. I wrote this example code mainly to demonstrate how to use transforms and before I figured out that you don’t have to retain an NSTimer object (the run loop will retain the timer object for you after it has been added). Normally I use timers to animate things, so I do agree that calling setNeedsDisplay:YES and using a timer is the proper way to animate.

One side note on performSelector:withObject:afterDelay:. You can cancel a delayed method call with cancelPreviousPerformRequestsWithTarget:selector:object: or cancelPreviousPerformRequestsWithTarget:. This is nice, because you can filter delayed method calls by using the single argument as a key.

}

}

Since you have the freedom to choose the selector, target and the single argument and the ability to cancel delayed requests based on the arguments used to create the request, using performSelector:withObject:afterDelay: and cancelPreviousPerformRequestsWithTarget:selector:object: is a convenient way to organize timed actions. Animations that require high precision should stick to using NSTimers, but all other cases are well suited for using performSelector:withObject:afterDelay:.

–zootbobbalu