0%

用CAShapeLayer动画绘制CGPath

这是什么?

此文将讲解通过形状图层CAShaperLayerstrokeStartstrokeEnd来实现动画绘制路径CGPath,此文是By Ole Begemann创建于December 18, 2010,当时是发布iOS SDK 4.2时CAShapeLayer新增加的两个属性strokeStartstrokeEnd,这两个值是两个浮点数取值范围0.0~1.0,用来表明形状图层所指向的路径在绘制开始和结束路径中的相对位置。

strokeStart默认值是0.0,strokeEnd默认值是1.0,显然这会导致形状图层的路径将一整个被绘制。假如,你想说,如果设置了layer.strokeEnd = 0.5f,只让她绘制前半部分,那该多好。

真正有趣的事情是这些接口都是可动画的。通过动画绘制strokeEnd从0.0到1.0在几秒内,我们就能很容易自己绘制路径像下面这样写:

1
2
3
4
5
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = 10.0;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[self.pathLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"];

最后,再添加第二个图层包含一个铅笔图片,使用关键帧动画 CAKeyframeAnimation来让它随着这个路径以相同的速度绘制,就可以达到完美的错觉效果:

1
2
3
4
5
CAKeyframeAnimation *penAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
penAnimation.duration = 10.0;
penAnimation.path = self.pathLayer.path;
penAnimation.calculationMode = kCAAnimationPaced;
[self.penLayer addAnimation:penAnimation forKey:@"penAnimation"];

绘制普通路径效果视频

下载地址

这个对文本一样有效;我们只需要把字符转化成CGPathCore Text提供了那样的功能的函数,CTFontCreatePathForGlyph( )。为了使用它,我们需要创建一个带属性的字符串用我们想要渲染的文本,先把它们分割成行在分割成一个个字符。在把所有的字符转换成路径后,我们以子路径方式把它添加到一个单个的CGPath路径中。更多细节可以查看Ohmu写的Low-level text rendering这篇文章。结果看以来非常的炫酷:

绘制文字路径效果视频

下载地址

从Github上获得iPad版的样品工程

你将学到的知识点

  • 使用CAShapeLayerstrokeStartstrokeEnd来实现路径动画,比较高级复杂的效果像google的下拉刷新转圈就可以从这里引申去实现。
  • CABasicAnimationCABasicAnimation使用
  • 深入理解CAShapeLayerCALayer
  • 通过文本创建路径,核心函数CTFontCreatePathForGlyph()

补充说明

1
2
3
4
5
6
7
8
9
10
11
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.animationLayer.bounds;
pathLayer.bounds = pathRect;
pathLayer.geometryFlipped = YES;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor blackColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 10.0f;
pathLayer.lineJoin = kCALineJoinBevel;

[self.animationLayer addSublayer:pathLayer];

有一点非常重要,CALayer在iOS系统中相对坐标系是以屏幕左上top-left为坐标原点的,在Mac OS X上以坐下bottom-left为坐标原点,但是可以通过CALayer的接口geometryFlipped垂直翻转坐标系,这个值默认是NO,设置成YES就可以把坐标系转换成左下bottom-left了,这里作者使用的左下bottom-left的坐标系。

1
@property(getter=isGeometryFlipped) BOOL geometryFlipped;

关于这个属性使用时需要特别注意

  1. 翻转会同时作用于它的子图层
  2. 即使这个属性设置成YES,图片的orientation仍然是不变的(也就是说当设置flipped=YESflipped=NO时一个CGImageRef储存在contents接口中的内容将会显示一致,赋值并不会真正变换底层的图层)

pathLayer动画实现原理

  1. 先创建一个动画用的图层animationLayer类型CALayer,用来充当动画的画布。
  2. 创建真正的路径图层pathLayer类型为CAShapeLayer,让它的坐标系垂直翻转,并且让图层宽高同时向内收缩100个点,通过CGRectInset(CGRect rect, CGFloat dx, CGFloat dy)实现
  3. pathLayer添加到animationLayer的子图层中去
  4. 创建一个铅笔图层penLayer类型为CALayer,把它添加到pathLayer
  5. pathLayer添加CABasicAnimation动画,动画属性为strokeEnd
  6. penLayer添加CAKeyframeAnimation动画,动画属性为position

textLayer动画实现原理

  1. 先创建一个动画用的图层animationLayer类型CALayer,用来充当动画的画布
  2. Create path from text,See:http://www.codeproject.com/KB/iPhone/Glyph.aspx,最终保存到一个类型为CGMutablePathRef的letter中
  3. 通过letter来创建文字UIBezierPath类型的path
  4. 通过path再创建CAShapeLayerpathLayer,并且把pathLayer添加到animationLayer中去
  5. 创建一个铅笔图层penLayer类型为CALayer,把它添加到pathLayer
  6. pathLayer添加CABasicAnimation动画,动画属性为strokeEnd
  7. penLayer添加CAKeyframeAnimation动画,动画属性为position

修复一处bug

重复点击UISegmentedControl导致铅笔消失,这是设置了 penAnimation.delegate = self;在代理方法里面没有判断结束直接将设置self.penLayer.hidden = YES,导致连续切换时铅笔不见了,要修复这个bug只需加一个判断 if (flag) self.penLayer.hidden = YES;即可,这样的意思是只有当动画完成时才设置self.penLayer.hidden的值,好了现在已经非常完美了,快去动手自己试试吧!🍺

备注:欢迎转载,但请一定注明出处! http://blog.wangruofeng007.com