I have a custom view in an NSStatusItem object.
This view displays icons. It’s also able to show a progress, but you have to call [self.statusitemview setProgressValue:theValue];
I have a set of icons, and it chooses the right one using this value.
This seems very jerky, because the executed process doesn’t send updates all the time.
So I would like to animate this.
I would like to call the animation like you can with other cocoa-controls:
[[self.statusItemView animator] setProgressValue:value];
If that’s at all possible
What is the proper way to do this?
I wouldn’t want to use an NSTimer.
EDIT
The images are drawn using the drawRect: method
Here’s the code:
- (void)drawRect:(NSRect)dirtyRect
{
if (self.isHighlighted) {
[self.statusItem drawStatusBarBackgroundInRect:self.bounds withHighlight:YES];
}
[self drawIcon];
}
- (void)drawIcon {
if (!self.showsProgress) {
[self drawIconWithName:@"statusItem"];
} else {
[self drawProgressIcon];
}
}
- (void)drawProgressIcon {
NSString *pushed = (self.isHighlighted)?@"-pushed":@"";
int iconValue = ((self.progressValue / (float)kStatusItemViewMaxValue) * kStatusItemViewProgressStates);
[self drawIconWithName:[NSString stringWithFormat:@"statusItem%@-%d", pushed, iconValue]];
}
- (void)drawIconWithName:(NSString *)iconName {
if (self.isHighlighted && !self.showsProgress) iconName = [iconName stringByAppendingString:@"-pushed"];
NSImage *icon = [NSImage imageNamed:iconName];
NSRect drawingRect = NSCenterRect(self.bounds, icon);
[icon drawInRect:drawingRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
}
- (void)setProgressValue:(int)progressValue {
if (progressValue > kStatusItemViewMaxValue || progressValue < 0) {
@throw [NSException exceptionWithName:@"Invalid Progress Value"
reason:[NSString stringWithFormat:@"The value %d id invalid. Range {0 - %d}", progressValue, kStatusItemViewMaxValue]
userInfo:nil];
}
_progressValue = progressValue;
[self setNeedsDisplay:YES];
}
- (void)setShowsProgress:(BOOL)showsProgress {
if (!showsProgress) self.progressValue = 0;
_showsProgress = showsProgress;
[self setNeedsDisplay:YES];
}
It has to be possible somehow.
Since standard controls from Apple are drawn using the drawRect:, but have smooth animations…
To animate custom properties, you need to make your view conform to the
NSAnimatablePropertyContainerprotocol.You can then set up multiple custom properties as animatable (in addition to the properties already supported by
NSView), and then you can simply use your views’animatorproxy to animate the properties:Apart from making animation very simple, it also allows you to animate multiple objects simultaneously using an
NSAnimationContext:You can also set the duration and supply a completion handler block:
For a standard
NSViewobject, if you want to add animation support to a property in your view, you just need to override the+defaultAnimationForKey:method in your view and return an animation for the property:I’ve created a simple sample project that shows how to animate multiple properties of a view simultaneously using the
NSAnimatablePropertyContainerprotocol.All your view needs to do to update successfully is make sure that
setNeedsDisplay:YESis called when any of the animatable properties are modified. You can then get the values of those properties in yourdrawRect:method and update the animation based on those values.