如何使用Core Animation创建自定义缓动功能?

Mar*_*man 111 iphone cocoa-touch core-animation tween

我在iOS中很好地CALayer使用CGPath(QuadCurve)动画.但是我想使用一个比Apple 提供的更有趣的缓动功能(EaseIn/EaseOut等).例如,弹跳或弹性功能.

这些东西可以与MediaTimingFunction(bezier)一起使用:

在此输入图像描述

但我想创建更复杂的计时功能.问题是媒体时间似乎需要一个立方贝塞尔,它不足以产生这些效果:

http://wiki.sparrow-framework.org/_media/manual/transitions.png

代码创建上面是很简单的在其他框架中,这使得这个非常令人沮丧.请注意,曲线是将输入时间映射到输出时间(Tt曲线)而不是时间 - 位置曲线.例如,easeOutBounce(T)= t返回一个新的t.然后该t用于绘制运动(或任何我们应该动画的属性).

所以,我想创建一个复杂的自定义,CAMediaTimingFunction但我不知道如何做到这一点,或者甚至可能吗?还有其他选择吗?

编辑:

这是步骤的具体示例.很有教育意义

  1. 我想沿着从a点到b点的直线设置对象的动画,但我希望它使用上面的easeOutBounce曲线沿着直线"反弹"它的移动.这意味着它将遵循从ab的精确线,但是将以比使用当前基于bezier的CAMediaTimingFunction更复杂的方式加速和减速.

  2. 让我们使用CGPath指定任意曲线移动.它应该仍然沿着该曲线移动,但它应该以与线示例中相同的方式加速和减速.

从理论上讲,我认为它应该像这样工作:

让我们将运动曲线描述为关键帧动画移动(t)= p,其中t是时间[0..1],p是在时间t计算的位置.因此,move(0)返回曲线开始处的位置,移动(0.5)精确中间并移动(1)结束.使用定时功能时间(T)= t来提供移动t值应该给我想要的东西.对于弹跳效果,定时功能应该返回相同的时间(0.8)时间(0.8)的t值(仅作为示例).只需更换计时功能即可获得不同的效果.

(是的,可以通过创建和连接来回的四个线段进行线条弹跳,但这不是必需的.毕竟,它只是一个简单的线性函数,它将时间值映射到位置.)

我希望我在这里有意义.

Jes*_*sen 47

我找到了这个:

Cocoa with Love - 核心动画中的参数加速曲线

但我认为使用块可以使它更简单,更易读.所以我们可以在CAKeyframeAnimation上定义一个如下所示的类别:

CAKeyframeAnimation + Parametric.h:

// this should be a function that takes a time value between 
//  0.0 and 1.0 (where 0.0 is the beginning of the animation
//  and 1.0 is the end) and returns a scale factor where 0.0
//  would produce the starting value and 1.0 would produce the
//  ending value
typedef double (^KeyframeParametricBlock)(double);

@interface CAKeyframeAnimation (Parametric)

+ (id)animationWithKeyPath:(NSString *)path 
      function:(KeyframeParametricBlock)block
      fromValue:(double)fromValue
      toValue:(double)toValue;
Run Code Online (Sandbox Code Playgroud)

CAKeyframeAnimation + Parametric.m:

@implementation CAKeyframeAnimation (Parametric)

+ (id)animationWithKeyPath:(NSString *)path 
      function:(KeyframeParametricBlock)block
      fromValue:(double)fromValue
      toValue:(double)toValue {
  // get a keyframe animation to set up
  CAKeyframeAnimation *animation = 
    [CAKeyframeAnimation animationWithKeyPath:path];
  // break the time into steps
  //  (the more steps, the smoother the animation)
  NSUInteger steps = 100;
  NSMutableArray *values = [NSMutableArray arrayWithCapacity:steps];
  double time = 0.0;
  double timeStep = 1.0 / (double)(steps - 1);
  for(NSUInteger i = 0; i < steps; i++) {
    double value = fromValue + (block(time) * (toValue - fromValue));
    [values addObject:[NSNumber numberWithDouble:value]];
    time += timeStep;
  }
  // we want linear animation between keyframes, with equal time steps
  animation.calculationMode = kCAAnimationLinear;
  // set keyframes and we're done
  [animation setValues:values];
  return(animation);
}

@end
Run Code Online (Sandbox Code Playgroud)

现在用法看起来像这样:

// define a parametric function
KeyframeParametricBlock function = ^double(double time) {
  return(1.0 - pow((1.0 - time), 2.0));
};

if (layer) {
  [CATransaction begin];
    [CATransaction 
      setValue:[NSNumber numberWithFloat:2.5]
      forKey:kCATransactionAnimationDuration];

    // make an animation
    CAAnimation *drop = [CAKeyframeAnimation 
      animationWithKeyPath:@"position.y"
      function:function fromValue:30.0 toValue:450.0];
    // use it
    [layer addAnimation:drop forKey:@"position"];

  [CATransaction commit];
}
Run Code Online (Sandbox Code Playgroud)

我知道它可能不像你想要的那么简单,但它是一个开始.


Olg*_*eva 29

从iOS 10开始,使用两个新的计时对象可以更轻松地创建自定义计时功能.

1)UICubicTimingParameters允许将三次Bézier曲线定义为缓动函数.

let cubicTimingParameters = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.25, y: 0.1), controlPoint2: CGPoint(x: 0.25, y: 1))
let animator = UIViewPropertyAnimator(duration: 0.3, timingParameters: cubicTimingParameters)
Run Code Online (Sandbox Code Playgroud)

或者只是在动画师初始化时使用控制点

let controlPoint1 = CGPoint(x: 0.25, y: 0.1)
let controlPoint2 = CGPoint(x: 0.25, y: 1)
let animator = UIViewPropertyAnimator(duration: 0.3, controlPoint1: controlPoint1, controlPoint2: controlPoint2) 
Run Code Online (Sandbox Code Playgroud)

这个很棒的服务将有助于为曲线选择控制点.

2)UISpringTimingParameters允许开发人员操纵阻尼比,质量,刚度初始速度,以创建所需的弹簧行为.

let velocity = CGVector(dx: 1, dy: 0)
let springParameters = UISpringTimingParameters(mass: 1.8, stiffness: 330, damping: 33, initialVelocity: velocity)
let springAnimator = UIViewPropertyAnimator(duration: 0.0, timingParameters: springParameters)
Run Code Online (Sandbox Code Playgroud)

持续时间参数仍然在Animator中显示,但在弹簧定时时将被忽略.

如果这两个选项不够,您还可以通过确认UITimingCurveProvider协议来实现自己的时序曲线.

更多细节,如何使用不同的时序参数创建动画,您可以在文档中找到.

另外,请参阅2016年WWDC的UIKit动画和过渡进展.


fsa*_*int 13

创建自定义计时功能的一种方法是使用CAMediaTimingFunction中的functionWithControlPoints :::: factory方法(还有一个相应的initWithControlPoints :::: init方法).这样做是为您的计时功能创建Bézier曲线.它不是任意曲线,但Bézier曲线非常强大且灵活.获取控制点的挂起需要一些练习.小贴士:大多数绘图程序都可以创建Bézier曲线.使用这些将为您提供关于您使用控制点表示的曲线的视觉反馈.

这个链接指向苹果的文档.关于如何从曲线构造预构建函数,有一个简短但有用的部分.

编辑:以下代码显示简单的反弹动画.为此,我创建了一个组合计时函数(计时 NSArray属性),并为动画的每个片段赋予不同的时间长度(keytimes属性).通过这种方式,您可以组合Bézier曲线,为动画构成更复杂的时序.是一篇关于这类动画的好文章,带有很好的示例代码.

- (void)viewDidLoad {
    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 50.0)];

    v.backgroundColor = [UIColor redColor];
    CGFloat y = self.view.bounds.size.height;
    v.center = CGPointMake(self.view.bounds.size.width/2.0, 50.0/2.0);
    [self.view addSubview:v];

    //[CATransaction begin];

    CAKeyframeAnimation * animation; 
    animation = [CAKeyframeAnimation animationWithKeyPath:@"position.y"]; 
    animation.duration = 3.0; 
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;

    NSMutableArray *values = [NSMutableArray array];
    NSMutableArray *timings = [NSMutableArray array];
    NSMutableArray *keytimes = [NSMutableArray array];

    //Start
    [values addObject:[NSNumber numberWithFloat:25.0]];
    [timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
    [keytimes addObject:[NSNumber numberWithFloat:0.0]];


    //Drop down
    [values addObject:[NSNumber numberWithFloat:y]];
    [timings addObject:GetTiming(kCAMediaTimingFunctionEaseOut)];
    [keytimes addObject:[NSNumber numberWithFloat:0.6]];


    // bounce up
    [values addObject:[NSNumber numberWithFloat:0.7 * y]];
    [timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
    [keytimes addObject:[NSNumber numberWithFloat:0.8]];


    // fihish down
    [values addObject:[NSNumber numberWithFloat:y]];
    [keytimes addObject:[NSNumber numberWithFloat:1.0]];
    //[timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];



    animation.values = values;
    animation.timingFunctions = timings;
    animation.keyTimes = keytimes;

    [v.layer addAnimation:animation forKey:nil];   

    //[CATransaction commit];

}
Run Code Online (Sandbox Code Playgroud)


CIF*_*ter 9

不确定你是否还在寻找,但PRTween在超越Core Animation开箱即用的能力方面看起来相当令人印象深刻,最显着的是自定义计时功能.它还包含许多(如果不是全部)各种Web框架提供的流行缓动曲线.