objective-c – 如何在更改文本时在NSTextField中为fadeIn fadeOut效果设置动画?

我正在尝试为NSTextField编写一个类别,它将添加一个方法setAnimatedStringValue.这个方法应该很好地淡出当前文本,然后设置新文本然后淡入.

以下是我的实施: –

- (void) setAnimatedStringValue:(Nsstring *)aString {

    if ([[self stringValue] isEqualToString:aString]) {
        return;
    }

    NSMutableDictionary *dict = Nil;

    NSViewAnimation *fadeOutAnim;
    dict = [NSDictionary dictionaryWithObjectsAndKeys:self,NSViewAnimationTargetKey,NSViewAnimationFadeOutEffect,NSViewAnimationEffectKey,nil];
    fadeOutAnim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:
                                                               dict,nil]];
    [fadeOutAnim setDuration:2];
    [fadeOutAnim setAnimationCurve:NSAnimationEaSEOut];
    [fadeOutAnim setAnimationBlockingMode:NSAnimationBlocking];

    NSViewAnimation *fadeInAnim;
    dict = [NSDictionary dictionaryWithObjectsAndKeys:self,NSViewAnimationFadeInEffect,nil];
    fadeInAnim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:
                                                                   dict,nil]];
    [fadeInAnim setDuration:3];
    [fadeInAnim setAnimationCurve:NSAnimationEaseIn];
    [fadeInAnim setAnimationBlockingMode:NSAnimationBlocking];

    [fadeOutAnim startAnimation];

    [self setStringValue:aString];

    [fadeInAnim startAnimation];
}

不用说,但上面的代码根本不起作用.我看到的唯一效果是在同一窗口上闪烁进度条.这可能是因为我试图“动画”它时阻止了主要的runloop.

请告知以上代码有什么问题.

附加说明:

setAnimatedStringValue始终由NSTimer调用,该NSTimer被添加到主NSRunLoop.

解决方法

我会采取刺:

在这里发现了几个问题.首先,整个事情被设置为阻塞,所以它将阻塞主线程5秒.这将转换为SPOD /挂起的用户.你可能希望这是非阻塞的,但它需要一些额外的机制来实现这一点.

此外,您正在使用NSAnimationEaSEOut进行淡出效果,这会受到已知错误的影响,导致动画向后运行. (谷歌的“NSAnimationEaSEOut向后”,你可以看到很多人都遇到了这个问题.)我在这个例子的两条曲线中使用了NSAnimationEaseIn.

我使用非阻塞动画制作了一个简单的例子.我不是说这是理想的方法(我发布了第二个答案,可以说更好),但它确实有效,并且可以作为你的起点.这是它的关键:

@interface NSTextField (AnimatedSetString)

- (void) setAnimatedStringValue:(Nsstring *)aString;

@end

@interface SOTextFieldAnimationDelegate : NSObject <NSAnimationDelegate>

- (id)initForSettingString: (Nsstring*)newString onTextField: (NSTextField*)tf;

@end

@implementation NSTextField (AnimatedSetString)

- (void) setAnimatedStringValue:(Nsstring *)aString
{
    if ([[self stringValue] isEqual: aString])
    {
        return;
    }

    [[[SOTextFieldAnimationDelegate alloc] initForSettingString: aString onTextField: self] autorelease];
}

@end


@implementation SOTextFieldAnimationDelegate
{
    Nsstring* _newString;
    NSAnimation* _fadeIn;
    NSAnimation* _fadeOut;
    NSTextField* _tf;
}

- (id)initForSettingString: (Nsstring*)newString onTextField: (NSTextField*)tf
{
    if (self = [super init])
    {
        _newString = [newString copy];
        _tf = [tf retain];

        [self retain]; // we'll autorelease ourselves when the animations are done.

        _fadeOut = [[NSViewAnimation alloc] initWithViewAnimations: @[ (@{
                                                                        NSViewAnimationTargetKey : tf,NSViewAnimationEffectKey : NSViewAnimationFadeOutEffect})] ];
        [_fadeOut setDuration:2];
        [_fadeOut setAnimationCurve: NSAnimationEaseIn];
        [_fadeOut setAnimationBlockingMode:NSAnimationNonblocking];
        _fadeOut.delegate = self;

        _fadeIn = [[NSViewAnimation alloc] initWithViewAnimations: @[ (@{
                                                                        NSViewAnimationTargetKey : tf,NSViewAnimationEffectKey : NSViewAnimationFadeInEffect})] ];
        [_fadeIn setDuration:3];
        [_fadeIn setAnimationCurve:NSAnimationEaseIn];
        [_fadeIn setAnimationBlockingMode:NSAnimationNonblocking];

        [_fadeOut startAnimation];
    }
    return self;
}

- (void)dealloc
{
    [_newString release];
    [_tf release];
    [_fadeOut release];
    [_fadeIn release];
    [super dealloc];
}

- (void)animationDidEnd:(NSAnimation*)animation
{
    if (_fadeOut == animation)
    {
        _fadeOut.delegate = nil;
        [_fadeOut release];
        _fadeOut = nil;

        _tf.hidden = YES;
        [_tf setStringValue: _newString];

        _fadeIn.delegate = self;
        [_fadeIn startAnimation];
    }
    else
    {
        _fadeIn.delegate = nil;
        [_fadeIn release];
        _fadeIn = nil;

        [self autorelease];
    }
}

@end

如果有基于块的API,这将是非常好的…它将节省必须实现此委托对象.

我把整个项目放在GitHub上.

相关文章

我正在用TitaniumDeveloper编写一个应用程序,它允许我使用Ja...
我的问题是当我尝试从UIWebView中调用我的AngularJS应用程序...
我想获取在我的Mac上运行的所有前台应用程序的应用程序图标....
我是一名PHP开发人员,我使用MVC模式和面向对象的代码.我真的...
OSX中的SetTimer在Windows中是否有任何等效功能?我正在使用...
我不确定引擎盖下到底发生了什么,但这是我的设置,示例代码和...