如何在NSTextField中改变文本时对fadeIn fadeOut效果进行动画处理? [英] How do I animate fadeIn fadeOut effect in NSTextField when changing its text?

查看:118
本文介绍了如何在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,NSViewAnimationTargetKey,
NSViewAnimationFadeInEffect,NSViewAnimationEffectKey,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 添加到 NSRunLoop

解决方案

我会尝试一下:



我在这里发现了一些问题。首先,这整个事情被设置为阻塞,因此它将阻塞主线程5秒钟。这将转换为用户作为SPOD /挂起。你可能希望这是非阻塞,但它需要一点点额外的机械,使这种情况发生。



此外,您使用 NSAnimationEaseOut 获得淡出效果,这是由已知的错误导致动画向后运行。 (Google forNSAnimationEaseOut backwards,您可以看到很多都遇到了这个问题。)我使用 NSAnimationEaseIn 为这个例子的两个曲线。 / p>

我得到这个工作与一个微不足道的例子与非阻塞动画。我不会说这是理想方法(我发布了第二个答案,可以说更好),但它的工作,并希望可以作为一个跳跃点为你。这里是它的关键:

  @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]; //当动画完成时,我们将自动释放自己。

_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];
[_fadeInsetAnimationBlockingMode: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为这...它会节省必须实现这个委托对象真的很好。



我把整个项目放在< a href =https://github.com/ipmcc/SOExamples/tree/master/animation/AnimTextField =nofollow> GitHub 。


I am trying to write a category for NSTextField which will add a new method setAnimatedStringValue. This method is supposed to nicely fade-out the current text, then set the new text and then fade that in.

Below is my implementation:-

- (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, NSViewAnimationTargetKey,
            NSViewAnimationFadeInEffect, NSViewAnimationEffectKey, 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];
}

Needless to say, but the above code does not work at all. The only effect I see is the flickering of a progress bar on the same window. That is possibly because I am blocking the main runloop while trying to "animate" it.

Please suggest what is wrong with the above code.

Additional note:

setAnimatedStringValue is always invoked by a NSTimer, which is added to the main NSRunLoop.

解决方案

I'll take a stab:

I found a couple problems here. First off, this whole thing is set up to be blocking, so it's going to block the main thread for 5 seconds. This will translate to the user as a SPOD/hang. You probably want this to be non-blocking, but it'll require a little bit of extra machinery to make that happen.

Also, you're using NSAnimationEaseOut for the fade out effect, which is effected by a known bug where it causes the animation to run backwards. (Google for "NSAnimationEaseOut backwards" and you can see that many have hit this problem.) I used NSAnimationEaseIn for both curves for this example.

I got this working for a trivial example with non-blocking animations. I'm not going to say that this is the ideal approach (I posted a second answer that arguably better), but it works, and can hopefully serve as a jumping off point for you. Here's the crux of it:

@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

It would be really nice if there were block-based API for this... it'd save having to implement this delegate object.

I put the whole project up on GitHub.

这篇关于如何在NSTextField中改变文本时对fadeIn fadeOut效果进行动画处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆