【问题标题】:NSSlider animationNSSlider 动画
【发布时间】:2023-03-12 16:14:01
【问题描述】:

如何在更改其浮点值时创建 NSSlider 动画。我正在尝试:

[[mySlider animator] setFloatValue:-5];

但这不起作用..只需更改没有动画的值。那么也许有人知道如何做到这一点?

提前致谢。

【问题讨论】:

    标签: macos cocoa nsslider


    【解决方案1】:

    好的 - 所以这并不像我希望的那样快速和漂亮,但它确实有效。 您实际上不能在滑块旋钮上使用动画师和核心动画 - 因为核心动画仅适用于图层,并且无法访问滑块图层中的旋钮值。

    所以我们不得不求助于手动动画滑块值。 由于我们在 Mac 上执行此操作 - 您可以使用 NSAnimation(在 iOS 上不可用)。

    NSAnimation 所做的很简单——它提供了一种计时/插值机制来允许您制作动画(与核心动画相反,它也连接到视图并处理对它们的更改)。

    要使用 NSAnimation - 你通常会继承它并覆盖 setCurrentProgress: 并把你的逻辑放在那里。

    以下是我的实现方式 - 我创建了一个名为 NSAnimationForSlider 的新 NSAnimation 子类

    NSAnimationForSlider.h:

    @interface NSAnimationForSlider : NSAnimation  
    {  
        NSSlider *delegateSlider;  
        float animateToValue;    
        double max;   
        double min;  
        float initValue;  
    }  
    @property (nonatomic, retain) NSSlider *delegateSlider;  
    @property (nonatomic, assign) float animateToValue;    
    @end  
    

    NSAnimationForSlider.m:

    #import "NSAnimationForSlider.h"
    
    @implementation NSAnimationForSlider
    @synthesize delegateSlider;
    @synthesize animateToValue;
    
    -(void)dealloc
    {
        [delegateSlider release], delegateSlider = nil;
    }
    
    -(void)startAnimation
    {
        //Setup initial values for every animation
        initValue = [delegateSlider floatValue];
        if (animateToValue >= initValue) {
            min = initValue;
            max = animateToValue;
        } else  {
            min = animateToValue;
            max = initValue;
        }
    
        [super startAnimation];
    }
    
    
    - (void)setCurrentProgress:(NSAnimationProgress)progress
    {
        [super setCurrentProgress:progress];
    
        double newValue;
        if (animateToValue >= initValue) {
            newValue = min + (max - min) * progress;        
        } else  {
            newValue = max - (max - min) * progress;
        }
    
        [delegateSlider setDoubleValue:newValue];
    }
    
    @end
    

    要使用它 - 您只需创建一个新的 NSAnimationForSlider,将您正在处理的滑块作为委托给它,并在每个动画之前将其设置为 animateToValue,然后启动动画。

    例如:

    slider = [[NSSlider alloc] initWithFrame:NSMakeRect(50, 150, 400, 25)];
    [slider setMaxValue:200];
    [slider setMinValue:50];
    [slider setDoubleValue:50];
    
    [[window contentView] addSubview:slider];
    
    NSAnimationForSlider *sliderAnimation = [[NSAnimationForSlider alloc] initWithDuration:2.0 animationCurve:NSAnimationEaseIn];
    [sliderAnimation setAnimationBlockingMode:NSAnimationNonblocking];
    [sliderAnimation setDelegateSlider:slider];
    [sliderAnimation setAnimateToValue:150];
    
    [sliderAnimation startAnimation];
    

    【讨论】:

    • 感谢您的回答,也许您可​​以说更准确的方法是如何做到这一点?因为我不明白你到底是什么意思。你说的基本动画是什么意思? “动画师”我认为是基本动画。
    • 我很快就会在我的桌面上为你写代码
    • 对,我们说的是 Mac。
    • 哇!这不是那么容易!非常非常非常非常感谢您的帮助!!!我会去测试和使用你的代码!再次哇,非常感谢你!!!
    • 很高兴 - 如果您发现问题或改进 - 将它们发回这里。祝你好运!
    【解决方案2】:

    您的方法有效,但有一些更简单的方法。

    可以使用动画代理,您只需要告诉它如何制作动画即可。 为此,您需要实现NSAnimatablePropertyContainer 协议中的defaultAnimationForKey: 方法。


    这是NSSlider 的一个简单子类,它执行此操作:

    #import "NSAnimatableSlider.h"
    #import <QuartzCore/QuartzCore.h>
    
    @implementation NSAnimatableSlider
    
    + (id)defaultAnimationForKey:(NSString *)key
    {
        if ([key isEqualToString:@"doubleValue"]) {
            return [CABasicAnimation animation];
        } else {
            return [super defaultAnimationForKey:key];
        }
    }
    
    @end
    

    现在您可以简单地使用动画代理:

    [self.slider.animator setDoubleValue:100.0];
    

    确保链接QuartzCore 框架。

    【讨论】:

    • 根据this example from Apple,您也可以通过类扩展来启用它。但是子类化不太可能干扰其他代码。
    猜你喜欢
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 2018-09-06
    相关资源
    最近更新 更多