1

NSStatusItem オブジェクトにカスタム ビューがあります。このビューにはアイコンが表示されます。進行状況を表示することもできますが、[self.statusitemview setProgressValue:theValue]; I have a set of icons を呼び出す必要があり、この値を使用して適切なアイコンを選択します。

実行されたプロセスが常に更新を送信するわけではないため、これは非常にぎくしゃくしています。だからこれをアニメ化したい。

他のココア コントロールと同じようにアニメーションを呼び出したいと思います: [[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: を使用して描画されるため、アニメーションはスムーズです...

4

2 に答える 2

5

To animate custom properties, you need to make your view conform to the NSAnimatablePropertyContainer protocol.

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' animator proxy to animate the properties:

yourObject.animator.propertyName = finalPropertyValue;

Apart from making animation very simple, it also allows you to animate multiple objects simultaneously using an NSAnimationContext:

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

You can also set the duration and supply a completion handler block:

[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5];
[[NSAnimationContext currentContext] setCompletionHandler:^{
    NSLog(@"animation finished");
}];
firstObject.animator.propertyName = finalPropertyValue1;
secondObject.animator.propertyName = finalPropertyValue2;
[NSAnimationContext endGrouping];

For a standard NSView object, 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:

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

I've created a simple sample project that shows how to animate multiple properties of a view simultaneously using the NSAnimatablePropertyContainer protocol.

All your view needs to do to update successfully is make sure that setNeedsDisplay:YES is called when any of the animatable properties are modified. You can then get the values of those properties in your drawRect: method and update the animation based on those values.

于 2012-10-16T01:55:07.137 に答える
-1

ここで同様の質問に答えました

animator でカスタム プロパティをアニメーション化することはできませんが、必要に応じてカスタム アニメーションを作成することはできますが、これは最善の方法ではありません。

更新 (カスタム アニメーション):

- (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];
}
于 2012-10-14T03:49:22.510 に答える