NSSlider анимация
Как я могу создать анимацию NSSlider при изменении ее значения с плавающей запятой. Я пытался:
[[mySlider animator] setFloatValue:-5];
но это не сработало... просто измените значение без анимации. Так может кто знает как это сделать?
Заранее спасибо.
3 ответа
Хорошо - так что это не так быстро и красиво, как я надеялся, но это работает. На самом деле вы не можете использовать аниматоры и Core Animation на регуляторе ползунка - потому что Core Animation работает только на слоях и нет доступа к значениям регулятора в слое слайдера.
Поэтому мы должны вместо этого прибегнуть к ручной анимации значения слайдера. Поскольку мы делаем это на Mac - вы можете использовать NSAnimation (которая недоступна на iOS).
Что NSAnimation делает просто - он предоставляет механизм синхронизации / интерполяции, чтобы позволить вам анимировать (в отличие от базовой анимации, которая также подключается к представлениям и обрабатывает их изменения).
Чтобы использовать 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];
Ваш метод работает, но есть кое-что намного более простое.
Вы можете использовать прокси аниматора, вам просто нужно рассказать, как его анимировать. Для этого вам необходимо реализовать 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
фреймворк.
Вот версия ответа IluTov Swift , установившаяfloatValue
с некоторой конфигурацией анимации:
override class func defaultAnimation(forKey key: NSAnimatablePropertyKey) -> Any? {
if key == "floatValue" {
let animation = CABasicAnimation()
animation.timingFunction = .init(name: .easeInEaseOut)
animation.duration = 0.2
return animation
} else {
return super.defaultAnimation(forKey: key)
}
}