使用CADisplayLink与CAMediaTimingFunction“结合"为UIView设置动画.(获得任意曲线) [英] animate a UIView using CADisplayLink 'combined' with CAMediaTimingFunction. (to get a arbitrary curve)

查看:44
本文介绍了使用CADisplayLink与CAMediaTimingFunction“结合"为UIView设置动画.(获得任意曲线)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆