どちらかを必要としない解決策はありません...
a)の内部をいじくり回すNSProgressIndicator
か、
b)RollYourOwn™。
だから私はあなたがバグを提出するべきだと思います。
少なくともOSX10.6.5以降では、indetermined-progress-indicatorのwantsLayer
プロパティをに設定するとYES
すぐに、アニメーションがすぐに停止します。これは、縮小されたテストアプリ(以下のコード)で確認できます。
animate:
繰り返し呼び出すことができる(10.5以降非推奨)と呼ばれるメソッドがありましたNSProgressIndicator
。これは役立つ場合があります(不確定な進行状況インジケーターの使用を参照)。
編集:
呼び出しanimate:
に続くdisplayIfNeeded
(編集2:ブレントが指摘したように、これは冗長です)タイマーからはまだ機能します。「かもしれない」とは、非推奨のAPIの使用がApp Storeで認可されているかどうか、またはこれがあなたにとってまったく重要かどうかがわからないことを意味します。
サンプルアプリ
1つのコントローラーを備えたシンプルなCocoaアプリ:
@interface ProgressTester : NSObject {
NSProgressIndicator *indicator;
}
@property (nonatomic, assign) IBOutlet NSProgressIndicator *indicator;
@property (nonatomic, assign, getter=isLayered) BOOL layered;
- (IBAction)toggleWantsLayer:(id)sender;
@end
@implementation ProgressTester
@synthesize indicator;
@dynamic layered;
- (BOOL)isLayered
{
return [indicator wantsLayer];
}
- (void)setLayered:(BOOL)wantsLayer
{
static NSString *layeredKey = @"layered";
[self willChangeValueForKey:layeredKey];
[indicator setWantsLayer:wantsLayer];
[self didChangeValueForKey:layeredKey];
}
- (void)awakeFromNib
{
// initialize/synchronize UI state
[self setLayered:NO];
[indicator startAnimation:self];
}
-(IBAction)toggleWantsLayer:(id)sender
{
self.layered = ! self.layered;
}
@end
NIBの場合:
- コントローラのインスタンス
- スタイルが決定されていない1つのNSProgressIndicator(
indicator
コントローラーのアウトレットに接続されている)
toggleWantsLayer:
コントローラをターゲットおよびアクションとして持つボタン
ブレントによって追加されました:
この回答の情報を使用して、NSProgressIndicatorの単純なサブクラスを作成しました。
http://www.pastie.org/1465755 http://www.pastie.org/1540277
私のテストでは、呼び出し-animate:
は。なしで正常に機能したことに注意してください-displayIfNeeded
。
必要に応じて自由に使用してください。でも、使っていただけたら、ぜひお聞かせください!
ダニエルによって追加されました:
パスティのサブクラスに関するいくつかのポイント:
initWithFrame:
initWithFrame:
の代わりにに電話する必要がありますinit
(編集3:更新されたスニペットで修正されました)。
タイマーを保持する必要はありません。
スケジュールを設定するNSTimer
と、関連するrunloopが実行されretain
、タイマーがinvalidate
dになるまで破棄されません。(編集3:同様に修正されました)。
タイマーを使用した保持サイクルの有力な候補があります。NSTimer
保持はターゲットを保持するため、タイマーを介してアニメーション化されているときにインジケーターが解放された場合、deallocはおそらく呼び出されません(エッジケースであることはわかっていますが...)(編集3:面倒も見てくれます)。
完全にはわかりませんがawakeFromNib
、KVOのセットアップはすでに行われているため、の実装は冗長だと思います。initWithFrame:
(編集3:更新されたスニペットで明確にされています)。
とは言うものの、私は個人的animationTimer
には、KVOのものを完全に取り除くために、セッターでタイマーの無効化を合成して処理しないことを好みます。(観察self
は私の快適ゾーンの少し外にあります。)
アンによって追加されました:
アーカイブ目的で最新のPastieリンクからスニペットを追加する:
ArchProgressIndicator.h
//
// ArchProgressIndicator.h
// Translate2
//
// Created by Brent Royal-Gordon on 1/15/11.
// Copyright 2011 Architechies. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface ArchProgressIndicator : NSProgressIndicator {
@private
NSTimer * animationTimer;
}
// Just like NSProgressIndicator, but works better in a layer-backed view.
@end
ArchProgressIndicator.m
//
// ArchProgressIndicator.m
// Translate2
//
// Created by Brent Royal-Gordon on 1/15/11.
// Copyright 2011 Architechies. All rights reserved.
//
#import "ArchProgressIndicator.h"
@interface ArchProgressIndicator ()
@property (assign) NSTimer * animationTimer;
@end
@implementation ArchProgressIndicator
@synthesize animationTimer;
- (void)addObserver {
[self addObserver:self forKeyPath:@"animationTimer" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:[ArchProgressIndicator class]];
}
- (id)initWithFrame:(NSRect)frameRect {
if ((self = [super initWithFrame:frameRect])) {
[self addObserver];
}
return self;
}
// -initWithFrame: may not be called if created by a nib file
- (void)awakeFromNib {
[self addObserver];
}
// Documentation lists this as the default for -animationDelay
static const NSTimeInterval ANIMATION_UPDATE_INTERVAL = 5.0/60.0;
- (void)startAnimation:(id)sender {
[super startAnimation:sender];
if([self layer]) {
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:ANIMATION_UPDATE_INTERVAL target:self selector:@selector(animate:) userInfo:nil repeats:YES];
}
}
- (void)stopAnimation:(id)sender {
self.animationTimer = nil;
[super stopAnimation:sender];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context == [ArchProgressIndicator class]) {
if([keyPath isEqual:@"animationTimer"]) {
if([change objectForKey:NSKeyValueChangeOldKey] != [NSNull null] && [change objectForKey:NSKeyValueChangeOldKey] != [change objectForKey:NSKeyValueChangeNewKey]) {
[[change objectForKey:NSKeyValueChangeOldKey] invalidate];
}
}
}
else {
return [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc {
[self removeObserver:self forKeyPath:@"animationTimer"];
[animationTimer invalidate];
[super dealloc];
}
@end