2015-04-29 28 views
7

Używam CADisplayLink do wyświetlania animacji, która po prostu interpoluje wartość i przerysowuje sam widok.animuj UIView używając "połączonego" CADisplayLink z CAMediaTimingFunction. (aby uzyskać dowolną krzywą)

np. Mam widok MyView i ma on właściwość value, po ustawieniu wartości dzwonię pod numer setNeedsDisplay, a widok wie, co należy narysować.

do animacji tego używam CADisplayLink i chcę, aby widok "zmienił" pomiędzy wartościami. Robię to tylko przez interpolację wartości z animacji za start i stop Wartość:

- (CGFloat)interpolatedValue:(CGFloat)sourceValue withValue:(CGFloat)targetValue forProgress:(CGFloat)progress;

teraz coraz postęp liniowy jest łatwe i coraz „specyficznej krzywej” (OK), ale chcę, aby być w stanie podjąć zaleta CAMediaTimingFunction to zrobić (lub jakaś inna wcześniejsza logika - nie chcę ponownie wymyślać koła ponownie ":)

+0

dlaczego korzystania CADisplayLink? to tylko zegar. A CAMediaTimingFunction jest po prostu zapisem kluczowych argumentów krzywej. sama nie robi krzywej. jeśli wszystko, czego chcesz, to własność niestandardowa uzyskująca pełne wsparcie dla Core Animation, która podobnie jak standardowa animowalna właściwość, powinieneś dziedziczyć CALayer. patrz 'Dodawanie właściwości niestandardowych do warstwy' w dokumencie Xcode. – SolaWing

Odpowiedz

3

Jest to niesamowity powód RSTiming, który może być przydatny w twoim przypadku. Można zdefiniować funkcje taktowania za pomocą standardowej funkcji CAMediaTimingFunction lub nawet zdefiniować niestandardowe za pomocą 2 punktów kontrolnych w celu zdefiniowania krzywej Beziera.

Jeśli mam konfigurację, może masz coś takiego:

ViewController

#import "ViewController.h" 
#import "AnimatedView.h" 
#include <stdlib.h> 

@interface ViewController() 

@property (nonatomic, strong) CADisplayLink *displayLink; 
@property (weak, nonatomic) IBOutlet AnimatedView *viewToAnimate; 

@end 

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateFrame)]; 
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
} 

- (void)updateFrame { 
    [self.viewToAnimate updateAnimation]; 
} 

- (IBAction)updateAnimationTapped:(id)sender { 
    self.viewToAnimate.value = arc4random_uniform(101)/100.0; 
    NSLog(@"Next animation value: %f", self.viewToAnimate.value); 
} 

@end 

AnimatedView

#import "AnimatedView.h" 
#import "RSTimingFunction.h" 

@interface AnimatedView() 
{ 
    CGFloat _lastValue; 
    CGFloat _progressStep; 
    CGFloat _currentProgress; 
} 

@property (nonatomic, strong) RSTimingFunction *animationProgress; 

@end 

@implementation AnimatedView 

- (instancetype)initWithCoder:(NSCoder *)aDecoder 
{ 
    if ((self = [super initWithCoder:aDecoder])) 
    { 
     _progressStep = 0.01; // defines animation speed 
     _currentProgress = 1.0; 
     self.animationProgress = [RSTimingFunction timingFunctionWithName:kRSTimingFunctionEaseInEaseOut]; 
    } 

    return self; 
} 

- (void)setValue:(CGFloat)value { 
    if (_value != value) 
    { 
     _lastValue = _value; 
     _value = value; 
     _currentProgress = 0.0; 
    } 
} 

- (void)updateAnimation 
{ 
    if (_currentProgress > 1.0) 
     return; 

    _currentProgress += _progressStep; 
    CGFloat currentAnimationValue = _lastValue + (_value - _lastValue) * [self.animationProgress valueForX:_currentProgress]; 

    self.alpha = currentAnimationValue; // as an example animate alpha 
} 

@end 

Jak powiedział można nawet ustawić 2 punktów kontrolnych stworzyć funkcję czasową wzorowaną na sześciennej krzywej Beziera.

self.animationProgress = [RSTimingFunction timingFunctionWithControlPoint1:CGPointMake(0.6, 0.6) controlPoint2:CGPointMake(0.1, 0.8)]; 

która będzie produkować następujące animacji rozrządu (produkowane przy użyciu CAMediaTimingFunction playground)

enter image description here