[英]Animating a 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];
}
它必須以某種方式。 由於Apple的標准控件是使用drawRect:繪制的,但動畫流暢...
要為自定義屬性設置動畫,您需要使視圖符合NSAnimatablePropertyContainer
協議。
然后,您可以將多個自定義屬性設置為動畫(除了NSView
已經支持的屬性之外),然后您只需使用視圖的animator
代理來設置屬性的動畫:
yourObject.animator.propertyName = finalPropertyValue;
除了使動畫非常簡單之外,它還允許您使用NSAnimationContext
同時為多個對象設置動畫:
[NSAnimationContext beginGrouping];
firstObject.animator.propertyName = finalPropertyValue1;
secondObject.animator.propertyName = finalPropertyValue2;
[NSAnimationContext endGrouping];
您還可以設置持續時間並提供完成處理程序塊:
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5];
[[NSAnimationContext currentContext] setCompletionHandler:^{
NSLog(@"animation finished");
}];
firstObject.animator.propertyName = finalPropertyValue1;
secondObject.animator.propertyName = finalPropertyValue2;
[NSAnimationContext endGrouping];
對於標准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];
}
}
我創建了一個簡單的示例項目 ,該項目展示了如何使用NSAnimatablePropertyContainer
協議同時為視圖的多個屬性設置動畫。
要成功更新所需的所有視圖都要確保在修改任何可動畫屬性時調用setNeedsDisplay:YES
。 然后,您可以在drawRect:
方法中獲取這些屬性的值,並根據這些值更新動畫。
我在這里回答了類似的問題
您無法使用動畫制作器為自定義屬性設置動畫,但如果需要,您可以編寫自定義動畫,但這不是最好的主意。
更新(自定義動畫):
- (void) scrollTick:(NSDictionary*) params
{
static NSTimeInterval timeStart = 0;
if(!timeStart)
timeStart = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval stTime = timeStart;
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval totalTime = [[params valueForKey:@"duration"] doubleValue];
if(currentTime > timeStart + totalTime)
{
currentTime = timeStart + totalTime;
timeStart = 0;
}
double progress = (currentTime - stTime)/totalTime;
progress = (sin(progress*3.14-3.14/2.0)+1.0)/2.0;
NSClipView* clip = [params valueForKey:@"target"];
float startValue = [[params valueForKey:@"from"] floatValue];
float endValue = [[params valueForKey:@"to"] floatValue];
float newValue = startValue + (endValue - startValue)*progress;
[self setProperty:newValue];
if(timeStart)
[self performSelectorOnMainThread:@selector(scrollTick:) withObject:params waitUntilDone:NO];
}
- (void) setAnimatedProperty:(float)newValue
{
NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithFloat:self.property], @"from",
[NSNumber numberWithFloat:newValue],@"to",
[NSNumber numberWithFloat:1.0],@"duration",
nil];
[self performSelectorOnMainThread:@selector(scrollTick:) withObject:params waitUntilDone:NO];
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.