使用CADisplayLink与CAMediaTimingFunction“结合"为UIView设置动画.(获得任意曲线) [英] animate a UIView using CADisplayLink 'combined' with CAMediaTimingFunction. (to get a arbitrary curve)
问题描述
我正在使用 CADisplayLink
制作视图动画,该动画只是插值并重绘视图本身.
例如我有一个视图 MyView
,它具有一个属性 value
,每当设置了值时,我都会调用 setNeedsDisplay
并且该视图知道要绘制什么.>
对此进行动画处理,我使用 CADisplayLink
,并且我希望视图在值之间变形".我只是通过从动画的开始和结束值插值来做到这一点:
-(CGFloat)interpolatedValue:(CGFloat)sourceValue withValue:(CGFloat)targetValue forProgress:(CGFloat)progress;
现在获得线性进展很容易,并且可以获得特定曲线"(确定),但是我希望能够利用 CAMediaTimingFunction
来做到这一点(或其他一些先前存在的逻辑-我不知道'不想再次发明轮子':)
有一个很棒的要旨 RSTiming
在您的情况下可能会很方便.您可以使用标准的CAMediaTimingFunction定义定时功能,甚至可以使用2个控制点定义自定义功能来定义贝塞尔曲线.
如果我进行了设置,您可能会遇到类似这样的情况:
ViewController
#import"ViewController.h"#import"AnimatedView.h"#include< stdlib.h>@interface ViewController()@属性(非原子的,强的)CADisplayLink * displayLink;@属性(弱,非原子)IBOutlet AnimatedView * viewToAnimate;@结尾@implementation ViewController-(void)viewDidLoad {[super viewDidLoad];self.displayLink = [CADisplayLink displayLinkWithTarget:self选择器:@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(@下一个动画值:%f",self.viewToAnimate.value);}@结尾
AnimatedView
#import"AnimatedView.h"#import"RSTimingFunction.h"@interface AnimatedView(){CGFloat _lastValue;CGFloat _progressStep;CGFloat _currentProgress;}@属性(非原子的,强的)RSTimingFunction * animationProgress;@结尾@implementation AnimatedView-(instancetype)initWithCoder:(NSCoder *)aDecoder{如果((self = [super initWithCoder:aDecoder]){_progressStep = 0.01;//定义动画速度_currentProgress = 1.0;self.animationProgress = [RSTimingFunction TimingFunctionWithName:kRSTimingFunctionEaseInEaseOut];}回归自我}-(void)setValue:(CGFloat)value {如果(_value!= value){_lastValue = _value;_value =值;_currentProgress = 0.0;}}-(void)updateAnimation{如果(_currentProgress> 1.0)返回;_currentProgress + = _progressStep;CGFloat currentAnimationValue = _lastValue +(_value-_lastValue)* [self.animationProgress valueForX:_currentProgress];self.alpha = currentAnimationValue;//作为示例,设置动画Alpha}@结尾
如上所述,您甚至可以设置2个控制点来创建基于三次贝塞尔曲线的计时函数.
self.animationProgress = [RSTimingFunction TimingFunctionWithControlPoint1:CGPointMake(0.6,0.6)controlPoint2:CGPointMake(0.1,0.8)];
将制作以下定时动画(使用 CAMediaTimingFunction游乐场制作)
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' :)
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)
这篇关于使用CADisplayLink与CAMediaTimingFunction“结合"为UIView设置动画.(获得任意曲线)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!