NSA*_*ict 1 cocoa animation core-animation nsview nsstatusitem
我在NSStatusItem对象中有一个自定义视图.此视图显示图标.它也能够显示进度,但你必须打电话给[self.statusitemview setProgressValue:theValue];
我有一组图标,并选择使用此值的正确图标.
这似乎非常生涩,因为执行的进程不会一直发送更新.所以我想动画这个.
我想像其他可可控制一样调用动画:[[self.statusItemView animator] setProgressValue:value];
如果那是可能的
这样做的正确方法是什么?我不想使用NSTimer.
编辑
使用drawRect:方法绘制图像
这是代码:
- (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];
}
Run Code Online (Sandbox Code Playgroud)
它必须以某种方式.由于Apple的标准控件是使用drawRect:绘制的,但动画流畅...
要为自定义属性设置动画,您需要使视图符合NSAnimatablePropertyContainer协议.
然后,您可以将多个自定义属性设置为动画(除了已支持的属性之外NSView),然后您只需使用视图的animator代理来设置属性的动画:
yourObject.animator.propertyName = finalPropertyValue;
Run Code Online (Sandbox Code Playgroud)
除了使动画非常简单之外,它还允许您使用以下方法同时为多个对象设置动画NSAnimationContext:
[NSAnimationContext beginGrouping];
firstObject.animator.propertyName = finalPropertyValue1;
secondObject.animator.propertyName = finalPropertyValue2;
[NSAnimationContext endGrouping];
Run Code Online (Sandbox Code Playgroud)
您还可以设置持续时间并提供完成处理程序块:
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5];
[[NSAnimationContext currentContext] setCompletionHandler:^{
NSLog(@"animation finished");
}];
firstObject.animator.propertyName = finalPropertyValue1;
secondObject.animator.propertyName = finalPropertyValue2;
[NSAnimationContext endGrouping];
Run Code Online (Sandbox Code Playgroud)
对于标准NSView对象,如果要向视图中的属性添加动画支持,则只需覆盖+defaultAnimationForKey:视图中的方法并返回属性的动画:
//declare the default animations for any keys we want to animate
+ (id)defaultAnimationForKey:(NSString *)key
{
//in this case, we want to add animation for our x and y keys
if ([key isEqualToString:@"x"] || [key isEqualToString:@"y"]) {
return [CABasicAnimation animation];
} else {
// Defer to super's implementation for any keys we don't specifically handle.
return [super defaultAnimationForKey:key];
}
}
Run Code Online (Sandbox Code Playgroud)
我已经创建了一个简单的示例项目,该项目展示了如何使用NSAnimatablePropertyContainer协议同时为视图的多个属性设置动画.
要成功更新所需的所有视图都要确保setNeedsDisplay:YES在修改任何可动画属性时调用它.然后,您可以在drawRect:方法中获取这些属性的值,并根据这些值更新动画.