Анимация NSSlider

Как я могу создать анимацию NSSlider при изменении ее значения с плавающей запятой. Я пытался:

[[mySlider animator] setFloatValue:-5];

но это не сработало.. просто измените значение без анимации. Так может кто знает как это сделать?

Заранее спасибо.


person Community    schedule 26.01.2012    source источник


Ответы (2)


Итак, это не так быстро и красиво, как я надеялся, но это работает. На самом деле вы не можете использовать аниматоры и базовую анимацию на ручке ползунка, потому что базовая анимация работает только со слоями и нет доступа к значениям ручки в слое ползунка.

Поэтому вместо этого нам приходится прибегать к ручной анимации значения ползунка. Поскольку мы делаем это на Mac, вы можете использовать NSAnimation (недоступно в iOS).

То, что делает NSAnimation, простое — он предоставляет механизм синхронизации/интерполяции, позволяющий ВАМ анимировать (в отличие от Core Animation, который также подключается к представлениям и обрабатывает их изменения).

Чтобы использовать NSAnimation - чаще всего вы подклассифицируете его и переопределите setCurrentProgress: и поместите туда свою логику.

Вот как я это реализовал: я создал новый подкласс NSAnimation с именем NSAnimationForSlider.

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];
person shein    schedule 26.01.2012
comment
Спасибо за ответ, может быть вы можете сказать точнее, как это сделать? потому что я не понял точно, что вы имеете в виду. Что вы имеете в виду под базовой анимацией? аниматор Я думаю, что это базовая анимация. - person ; 27.01.2012
comment
Я скоро буду за своим рабочим столом и попытаюсь написать это для вас в коде. - person shein; 27.01.2012
comment
Правильно, мы говорим о Mac. - person ; 27.01.2012
comment
Ух ты! Это не так легко! СПАСИБО ВАМ ОГРОМНОЕ за помощь!!! Пойду тестить и использовать Ваш код! Вау, еще раз большое спасибо!!! - person ; 28.01.2012
comment
Удовольствие мое - если вы обнаружите проблемы или улучшения - опубликуйте их здесь. Удачи! - person shein; 28.01.2012
comment
Пусть вас не смущает слайдерDelegate. Это НЕ фактический делегат, и он не будет получать обратные вызовы NSAnimationDelegate, вы все равно хотите установить какой-либо контроллер или делегат вашего приложения для делегата и реализовать там методы NSAnimationDelegate для получения обратных вызовов или обработки хода или завершения анимации. - person uchuugaka; 05.07.2013

Ваш метод работает, но есть кое-что гораздо проще.

Вы можете использовать прокси-сервер аниматора, вам просто нужно указать ему, как его анимировать. Для этого нужно реализовать метод defaultAnimationForKey: из протокола NSAnimatablePropertyContainer.


Вот простой подкласс 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.

person IluTov    schedule 24.10.2013
comment
Согласно этот пример от Apple, вы также можете включить его с помощью расширения класса. Но создание подклассов с меньшей вероятностью будет мешать другому коду. - person DarkDust; 02.03.2016