Re: Animation in Cocoa too slow? [was: Animation with CALayer?]
Re: Animation in Cocoa too slow? [was: Animation with CALayer?]
- Subject: Re: Animation in Cocoa too slow? [was: Animation with CALayer?]
- From: Troy Stephens <email@hidden>
- Date: Wed, 6 Feb 2008 16:46:36 -0800
On Feb 6, 2008, at 9:27 AM, alex wrote:
Hi there,
Thanks for this answer- From what I see below this looks like a
technique to animate the change from one value to another (and the
result being the width of the line animating).
I'm not sure if this will work for me- I was really looking for a
way to simply draw a rectangle that represents the meter level. I
don't want to animate this per se. Just the act of drawing the
rectangle repeatedly is the animation. This gets called periodically
and ideally should not interfere with user interaction. What I have
now works but the CPU usage is too high for me and I worry that this
will become more of an issue later. My testing has led me to blame
calling setNeedsDisplay, then waiting for the event loop, then the
drawRect call (and all the setup work around those calls).. All
that seems too slow and complex compared to what I "used to" do...
What I want to do is have a timer or thread that looks at a value
and draws a rectangle to represent it. Effectively I want to grab a
CGContextRef and draw to it periodically without all the repeated
setup work- for instance, create a transparent overlay view, grab
its CGContextRef and then draw when I need to (outside the event
loop). Is this still possible? Or recommended? I promise I won't
draw more often than the refresh rate. :)
Yes, it's quite possible. If you just want a bar display that
immediately updates each time the value changes, you can lock focus on
the view and redraw immediately each time the value changes. e.g.:
if ([view lockFocusIfCanDraw]) {
NSRect bounds = [view bounds];
CGFloat y = bounds.origin.y + (level value from 0.0 to 1.0) *
bounds.size.height;
[[NSColor blackColor] set];
NSRectFill(bounds));
[[NSColor greenColor] set];
NSRectFill(NSMakeRect(bounds.origin.x, bounds.origin.y,
bounds.size.width, y - bounds.origin.y));
[view unlockFocus];
}
How does Core Animation do its thing without hogging the CPU I wonder?
By virtue of a background render thread, that offloads much work to
the GPU.
Troy
On Feb 5, 2008, at 12:53 PM, Bill Dudney wrote:
Hi Alex,
I have an example that was going to be part of the book but ended
up not fitting in the flow of things (although I might end up
adding it back) that shows how to animate something like your audio
level meter. The app animates the width of a line changing but the
secret sauce can be applied to the length of the audio meter. The
secret sauce, 1 make sure to call setNeedsDisplay: when the audio
value changes, 2 implement the defaultAnimationForKey: method to
return the animation you want used with the audio value changes;
- (void)setDrawnLineWidth:(float)value {
[self willChangeValueForKey:@"drawnLineWidth"];
drawnLineWidth = value;
[self.path setLineWidth:drawnLineWidth];
[self setNeedsDisplay:YES];
[self didChangeValueForKey:@"drawnLineWidth"];
}
+ (id)defaultAnimationForKey:(NSString *)key {
static CABasicAnimation *drawnLineWidthBasicAnimation = nil;
if ([key isEqualToString:@"drawnLineWidth"]) {
if (drawnLineWidthBasicAnimation == nil) {
drawnLineWidthBasicAnimation = [[CABasicAnimation alloc]
init];
}
return drawnLineWidthBasicAnimation;
} else {
return [super defaultAnimationForKey:key];
}
}
Then when you change the audio level do something like this;
- (IBAction)setWidth:(id)sender {
[[self animator] setDrawnLineWidth:[sender floatValue]];
}
This example uses simple cocoa stuff that you already know (except
for the defaultAnimationForKey: method) so its quicker uptake than
getting your head wrapped around drawing with CA (which is
conceptually similar to appkit drawing but in details its quite
different). If you want or need to go that route keep in mind that
layers do not clip their sublayers by default and that you should
call display only when the layer needs to be redrawn not during
animation. The whole animation is done via the presentation and
render tree layers and if you call display a lot it will kill
performance because its got to push the content down onto the
render layer too often.
Animating the slider could use a similar approach and look a lot
like the 'turn on time machine' button in the time machine prefs
panel.
HTH,
-bd-
http://bill.dudney.net/roller/objc
On Feb 5, 2008, at 1:30 PM, alex wrote:
Hi there,
Hopefully this is the right list for this question. I haven't
found what I was looking for after searching the archives for the
"right" way to animate some graphics using cocoa.
I'm trying to draw two different things. One of them is an audio
level meter and the other is an effect similar to what the iPhone
"slide" graphic does on the lock screen on the iPhone.
(I have a mask that I slide a white blob around behind.)
I'm able to do both with an NSTimer that fires and then I issue a
[setNeedsDisplay] from the timer to update the animation. This
works fine and produces the expected results but seems to use way
too much CPU compared to what I've been able to do "back in the
day" using straight CG or worse Quickdraw. (I am not porting this
code from QD- I threw that code away, this is all new code.)
I've been looking at using CALayers to implement the drawing so
that I can call [display] rather than [setNeedsDisplay] with the
hopes that this would make the animations use less CPU.
What is the right way to approach this problem? (and please don't
suggest using Shark to optimize my code as that is a given and
will be done after I determine what the best course of code will
be).
thanks,
alex
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
--
Troy Stephens
Cocoa Frameworks
Apple, Inc.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden