Animate a UIView using CADisplayLink “together” with CAMediaTimingFunction. (to get an arbitrary curve)

I use CADisplayLink to create a view animation that simply interpolates the value and redraws the view.

eg. I have a MyView and it has a value property when the value is set. I call setNeedsDisplay and the view knows what to draw.

to bring this to life, I use CADisplayLink , and I want the morph representation between the values. I do this by simply interpolating the value from the start and stop of the animation. Value:

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

Now getting a linear stroke is easy and getting a “concrete curve” (ok), but I want to be able to use the CAMediaTimingFunction for this (or some other existing logic), I don't want to reinvent the wheel again :)

+7
ios core-animation uiview
source share
1 answer

Here is this amazing gist RSTiming , which may be convenient in your case. You can define synchronization functions using either the standard CAMediaTimingFunction, or even define custom functions using 2 breakpoints to define a bezier curve.

If I have your setup, you might have something like this:

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 

As already mentioned, you can even set 2 control points to create a synchronization function modeled on a cubic Bezier curve.

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

Which will create the following temporary animation (created using the CAMediaTimingFunction playground )

enter image description here

+3
source share

All Articles