在第八章中,我们给时钟项目添加了动画。看起来很赞,但是如果有合适的缓冲函数就更好了。在显示世界中,钟表指针转动的时候,通常起步很慢,然后迅速啪地一声,最后缓冲到终点。但是标准的缓冲函数在这里每一个适合它,那该如何创建一个新的呢?

除了+functionWithName:之外,CAMediaTimingFunction同样有另一个构造函数,一个有四个浮点参数的+functionWithControlPoints::::(注意这里奇怪的语法,并没有包含具体每个参数的名称,这在objective-C中是合法的,但是却违反了苹果对方法命名的指导方针,而且看起来是一个奇怪的设计)。

使用这个方法,我们可以创建一个自定义的缓冲函数,来匹配我们的时钟动画,为了理解如何使用这个方法,我们要了解一些CAMediaTimingFunction是如何工作的。

三次贝塞尔曲线

CAMediaTimingFunction函数的主要原则在于它把输入的时间转换成起点和终点之间成比例的改变。我们可以用一个简单的图标来解释,横轴代表时间,纵轴代表改变的量,于是线性的缓冲就是一条从起点开始的简单的斜线(图10.1)。

 自定义缓冲函数(缓冲 10.2)

图10.1 线性缓冲函数的图像

这条曲线的斜率代表了速度,斜率的改变代表了加速度,原则上来说,任何加速的曲线都可以用这种图像来表示,但是CAMediaTimingFunction使用了一个叫做三次贝塞尔曲线的函数,它只可以产出指定缓冲函数的子集(我们之前在第八章中创建CAKeyframeAnimation路径的时候提到过三次贝塞尔曲线)。

你或许会回想起,一个三次贝塞尔曲线通过四个点来定义,第一个和最后一个点代表了曲线的起点和终点,剩下中间两个点叫做控制点,因为它们控制了曲线的形状,贝塞尔曲线的控制点其实是位于曲线之外的点,也就是说曲线并不一定要穿过它们。你可以把它们想象成吸引经过它们曲线的磁铁。

图10.2展示了一个三次贝塞尔缓冲函数的例子

自定义缓冲函数(缓冲 10.2)

图10.2 三次贝塞尔缓冲函数

实际上它是一个很奇怪的函数,先加速,然后减速,最后快到达终点的时候又加速,那么标准的缓冲函数又该如何用图像来表示呢?

CAMediaTimingFunction有一个叫做-getControlPointAtIndex:values:的方法,可以用来检索曲线的点,这个方法的设计的确有点奇怪(或许也就只有苹果能回答为什么不简单返回一个CGPoint),但是使用它我们可以找到标准缓冲函数的点,然后用UIBezierPathCAShapeLayer来把它画出来。

曲线的起始和终点始终是{0, 0}和{1, 1},于是我们只需要检索曲线的第二个和第三个点(控制点)。具体代码见清单10.4。所有的标准缓冲函数的图像见图10.3。

清单10.4 使用UIBezierPath绘制CAMediaTimingFunction

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *layerView;
 4 
 5 @end
 6 
 7 @implementation ViewController
 8 
 9 - (void)viewDidLoad
10 {
11     [super viewDidLoad];
12     //create timing function
13     CAMediaTimingFunction *function = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
14     //get control points
15     CGPoint controlPoint1, controlPoint2;
16     [function getControlPointAtIndex:1 values:(float *)&controlPoint1];
17     [function getControlPointAtIndex:2 values:(float *)&controlPoint2];
18     //create curve
19     UIBezierPath *path = [[UIBezierPath alloc] init];
20     [path moveToPoint:CGPointZero];
21     [path addCurveToPoint:CGPointMake(1, 1)
22             controlPoint1:controlPoint1 controlPoint2:controlPoint2];
23     //scale the path up to a reasonable size for display
24     [path applyTransform:CGAffineTransformMakeScale(200, 200)];
25     //create shape layer
26     CAShapeLayer *shapeLayer = [CAShapeLayer layer];
27     shapeLayer.strokeColor = [UIColor redColor].CGColor;
28     shapeLayer.fillColor = [UIColor clearColor].CGColor;
29     shapeLayer.lineWidth = 4.0f;
30     shapeLayer.path = path.CGPath;
31     [self.layerView.layer addSublayer:shapeLayer];
32     //flip geometry so that 0,0 is in the bottom-left
33     self.layerView.layer.geometryFlipped = YES;
34 }
35 
36 @end
View Code

相关文章:

  • 2022-12-23
  • 2021-07-21
  • 2022-12-23
  • 2021-07-10
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-19
猜你喜欢
  • 2022-02-03
  • 2022-12-23
  • 2021-05-24
  • 2021-06-21
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案