问题
I am using a CADisplayLink
to do a view animation that just interpolates a value and redraws the view itself.
e.g. I have a view MyView
and it has a property value
, whenever value is set I call setNeedsDisplay
and the view knows what to draw.
to animate this I use CADisplayLink
and I want the view to 'morph' between values. I do this by just interpolating the value from the animation's start and stop Value:
- (CGFloat)interpolatedValue:(CGFloat)sourceValue withValue:(CGFloat)targetValue forProgress:(CGFloat)progress;
now getting a linear progress is easy and getting a 'specific curve' (ok) but I want to be able to take advantage of CAMediaTimingFunction
to do this (or some other preexisting logic - I don't want to reinvent the wheel again' :)
回答1:
There's this awesome gist RSTiming which might be handy in your case. You can define timing functions either using standard CAMediaTimingFunction or even define custom ones using 2 control points to define a bezier curve.
If I got your setup, you may 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 said you can even set 2 control points to create a timing function modelled on a cubic Bezier curve.
self.animationProgress = [RSTimingFunction timingFunctionWithControlPoint1:CGPointMake(0.6, 0.6) controlPoint2:CGPointMake(0.1, 0.8)];
Which will produce the following timing animation (produced using CAMediaTimingFunction playground)
来源:https://stackoverflow.com/questions/29938707/animate-a-uiview-using-cadisplaylink-combined-with-camediatimingfunction-to