2012-10-11 57 views
1

我在NSStatusItem對象中有一個自定義視圖。 此視圖顯示圖標。它也能夠顯示進度,但您必須致電[self.statusitemview setProgressValue:theValue]; 我有一組圖標,並使用此值選擇正確的圖標。動畫NSStatusItem

這似乎是非常生澀,因爲執行的進程不會始終發送更新。 所以我想動畫這個。

我想要像其他可可控件一樣調用動畫: [[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)[email protected]"-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]; 
} 

它有可能以某種方式。 由於來自蘋果標準控制使用的drawRect繪製:,但有流暢的動畫......

+0

您的狀態項目視圖是如何定義的?它有一層嗎?什麼setProgressValue:做什麼? –

+0

不幸的是,我使用drawRect實現它: – NSAddict

+0

和setProgressValue只是設置了一個ivar併發送了setNeedsDisplay:來更新它 – NSAddict

回答

5

要動畫自定義屬性,你需要讓你的看法符合NSAnimatablePropertyContainer協議。

然後,您可以設置多個自定義屬性爲動畫(除由NSView已經支持的屬性),然後你可以簡單地使用你的意見animator代理動畫屬性:

yourObject.animator.propertyName = finalPropertyValue; 

除了從製作動畫非常簡單,它也可以讓你的動畫多個對象同時使用NSAnimationContext

[NSAnimationContext beginGrouping]; 
firstObject.animator.propertyName = finalPropertyValue1; 
secondObject.animator.propertyName = finalPropertyValue2; 
[NSAnimationContext endGrouping]; 

您還可以設置時間,並提供一個完成處理BLO CK:

[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]; 
    } 
} 

我創建了一個簡單的sample project,它顯示瞭如何使用NSAnimatablePropertyContainer協議同時動畫化視圖的多個屬性。

所有視圖需要做的更新成功是確保setNeedsDisplay:YES被調用時,任何動畫的屬性被修改。然後,您可以在drawRect:方法中獲取這些屬性的值,並根據這些值更新動畫。

+0

非常感謝!我不敢相信這很簡單 – NSAddict

-1

我已經回答了類似的問題here

你不能用動畫動畫自定義屬性,但你可以編寫自定義動畫如果你需要,儘管這不是最好的主意。

更新(自定義動畫):

- (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]; 
} 
+0

你誤解了我的問題。它與NSProgressIndicator無關。我有屬於自己的屬性,它可以幫助我找到當前進度的正確圖標。但不是設置[self.statusItemView setProgressValue:0.5];看到它跳躍,我想它動畫到0.5。 – NSAddict

+0

您無法使用動畫製作動畫自定義屬性。你需要自定義動畫 - 我已經用自定義動畫示例(線性)更新了我的答案。 – Remizorrr

+0

這不是我正在尋找的東西。是的,我知道我不能使用animator屬性,但必須以某種方式使用core-animation來執行此操作。如有必要,我可以使用圖層。有辦法做到這一點,但我只在繪製它時才工作,而不是在將圖像設置爲內容時。 – NSAddict