没有任何解决方案不需要您...
a) 摸索内部结构NSProgressIndicator
或
b) Roll Your Own™。
所以我会说你应该提交一个错误。
至少在 OS X 10.6.5 及更高版本上,一旦您将 indetermined-progress-indicator 的wantsLayer
属性设置为YES
,动画会立即停止——您可以使用简化的测试应用程序(下面的代码)自行检查。
有一个名为animate:
(自 10.5 起已弃用)的方法,您可以反复调用它NSProgressIndicator
,这可能会对您有所帮助(请参阅使用不确定的进度指示器)。
编辑:
打电话animate:
其次是displayIfNeeded
(编辑2:正如布伦特所说,这是多余的)来自计时器仍然有效。“可能”只是意味着我不知道 App Store 是否允许使用已弃用的 API,或者这对您来说是否重要。
示例应用
带有一个控制器的简单 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中:
- 控制器实例
- 一个样式不确定的 NSProgressIndicator(连接到
indicator
控制器的出口)
- 以控制器为目标和
toggleWantsLayer:
动作的按钮
布伦特添加:
我使用这个答案中的信息编写了一个简单的 NSProgressIndicator 子类:
http://www.pastie.org/1465755 http://www.pastie.org/1540277
请注意,在我的测试中,-animate:
没有-displayIfNeeded
.
您可以随意使用它。不过,如果您使用它,我很乐意收到您的来信!
丹尼尔补充:
关于 Pastie 子类的几点说明:
initWithFrame:
应该调用 toinitWithFrame:
而不是init
(编辑 3:在更新的片段中修复)。
不需要保留计时器:
调度 anNSTimer
会导致关联的 runloop直到retain
计时器结束才释放它invalidate
(编辑 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