文档章节

Mask 动画

w
 walking_yxf
发布于 09/26 09:09
字数 1358
阅读 4
收藏 0

前言:很多动效都是多种动画的组合,有时候你可能只是需要其中某个动画,但面对庞杂的代码库或是教程,你可能比较困惑,本系列将复杂动效中不常见的动画效果拆解出来便于学习,授人以鱼不如授人以渔。

37334-81771f6702ae0923.gif

第一讲是来自 BubbleTransition 中最夺人眼球的形变动画。这个效果在 StarWars.iOS转场动效有两次应用,非常地炫酷;Raywenderlich.com 也出过一个教程来实现这种效果。

15.gif

BubbleTransition

一般而言,这种效果会使用 UIBezierPath + CAShapeLayer + maskLayer 搞定,但是我去看了看代码,上面的效果其实是下面这样实现的。

37334-f26ca3b5dbd9d756.gif

BubbleTransition 慢放

Are you kidding me? Are you kidding me? 不知道我为何说两遍的请去欣赏《拯救呆萌》三部曲最终篇《火星救援》。这个效果的开发者真是太有才了,仅仅通过组合视图+缩放这么简单的方法就实现了这个效果,天才。

在上面提到的另外两种效果则是使用提到的 UIBezierPath + CAShapeLayer + maskLayer 套路,关于 UIBezierPath + CAShapeLayer,简书上有一篇写得还不错,就是标题太炫酷,这篇文章示范了使用 UIBezierPath + CAShapeLayer 实现不规则视图,也可以使用上面的简单组合手法轻松实现,但如果面对更加复杂的图形,还是得靠 UIBezierPath + CAShapeLayer。

也许你听说过贝塞尔曲线,但在 iOS 里,UIBezierPath 不仅仅用于生成一条曲线,常规的矩形、圆形、圆角矩形以及椭圆都不在话下,是个普适性的图形对象。而 CAShapeLayer 则是 CALayer 的子类,正如类名描述一样,通过其path属性搭配 UIBezierPath 可以实现多种用普通手段难以实现的外形,以及一些线条动画(可以去看看上面提到的标题很炫酷的文章)。

而 maskLayer,你可能听说过遮罩之类的概念,很像你玩游戏探索地图时的效果,这里实际上指的是CALayer类的mask属性,也是个CALayer对象,UIView类有个maskView的属性,作用相似。其实 BubbleTransition 里作者的实现手法本身就是对 mask 这一概念的应用,真的是太天才了。

使用 UIBezierPath + CAShapeLayer + maskLayer 套路实现上面的效果慢放后是下面这样的,不知道原作者有没有对这两种效果进行过对比,老实说,我觉得原作者的手法实现的效果更好:

26.gif

NewBubbleTransition

上面方法的核心代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

//利用 UIBezierPath 生成一大一小两条椭形路径,ovalInRect 意思是生成紧贴矩形内部的椭圆,bubble 是 BubbleTransition 中的添加的背景视图,

let circleMaskPathInitial = UIBezierPath(ovalInRect: bubble.frame)

let finalRect = CGRectInset(bubble.frame, -1000, -1000)

let circleMaskPathFinal = UIBezierPath(ovalInRect: finalRect)

//用 CAShapeLayer 作为 mask

let maskLayer = CAShapeLayer()

maskLayer.path = circleMaskPathFinal.CGPath

presentedControllerView.layer.mask = maskLayer

//对 CAShapeLayer 的 path 属性进行动画

let maskLayerAnimation = CABasicAnimation(keyPath: "path")

maskLayerAnimation.fromValue = circleMaskPathInitial.CGPath

maskLayerAnimation.toValue = circleMaskPathFinal.CGPath

maskLayerAnimation.duration = self.transitionDuration(transitionContext)

maskLayer.addAnimation(maskLayerAnimation, forKey: "path")

来点不一样的形状,当然从效果上来讲这个形状放在这里不好看。该例子仅作示范。

27.gif

quincunx.gif

生成梅花形状曲线的代码:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

let width = presentedControllerView.frame.width

let height = presentedControllerView.frame.height

 

let circleMaskPathInitial = UIBezierPath()

circleMaskPathInitial.moveToPoint(CGPoint(x: 0, y: height))

circleMaskPathInitial.addArcWithCenter(CGPoint(x: width / 4, y: height), radius: width / 4, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 3 / 2), clockwise: true)

circleMaskPathInitial.addArcWithCenter(CGPoint(x: width / 2, y: height - width / 4), radius: width / 4, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 2), clockwise: true)

circleMaskPathInitial.addArcWithCenter(CGPoint(x: width * 3 / 4, y: height), radius: width / 4, startAngle: CGFloat(M_PI * 3 / 2), endAngle:CGFloat(M_PI * 2), clockwise: true)

circleMaskPathInitial.moveToPoint(CGPoint(x: 0, y: height))

circleMaskPathInitial.closePath()

 

let circleMaskPathFinal = UIBezierPath()

circleMaskPathFinal.moveToPoint(CGPoint(x: -width, y: height))

circleMaskPathFinal.addArcWithCenter(CGPoint(x: 0, y: height), radius: height, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 3 / 2), clockwise: true)

circleMaskPathFinal.addArcWithCenter(CGPoint(x: width / 2, y: 0), radius: width / 2, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 2), clockwise: true)

circleMaskPathFinal.addArcWithCenter(CGPoint(x: width, y: height), radius: height, startAngle: CGFloat(M_PI * 3 / 2), endAngle: CGFloat(M_PI * 2), clockwise: true)

circleMaskPathFinal.moveToPoint(CGPoint(x: -width, y: height))

circleMaskPathFinal.closePath()

37334-1141ecdd38e818cb.png

示意图

类方法bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:用于添加圆弧,clockwise参数指示绘制的方向,true时沿顺时针方向绘制,false时沿逆时针方向绘制。下图是该方法文档中的坐标示意图:

37334-0ffaf490f31275ac.png

Angles in the default coordinate system

在绘制上面的梅花形状的曲线时,注意起始和终点的曲线保持整体的绘制方向一致,不然动画会很奇怪。

总结

差点搞了个大乌龙,不过见识到 BubbleTransition 的实现手段,现在就有两种手段来实现这类效果:

  • 尺寸更大的圆角矩形视图充当背景

  • UIBezierPath + CAShapeLayer + maskLayer

我对 BubbleTransition 的手法真是佩服得五体投地,就这么简单地搞定了,UIBezierPath + CAShapeLayer + maskLayer 的很多场景都可以使用这个手法替代,代价也不高。当然面对更复杂的曲线视图,还是用后者比较省心。

UIBezierPath + CAShapeLayer + maskLayer 的组合拳非常适合实现一些不规则的视图,像曲线菜单或任务栏,波纹视图,灌水视图等等,发挥下你的想象力吧。

本文转载自:http://www.cocoachina.com/ios/20160214/15250.html

共有 人打赏支持
上一篇: iOS 官方文档
下一篇: 自动布局相关
w
粉丝 1
博文 30
码字总数 11321
作品 0
武汉
私信 提问
Unity动画丨10.扛起木头动画的播放和AvatarMask的作用

1、设置扛起木头的动画Animation Clips 2、给Player新建Hold Log动画层,添加进抗木头Animation Clips,并将动画层权重Weight设置为1 两层不同的动画层都为动画控制器Animator Controller服务...

weixin_38239050
04/08
0
0
iOS 动画十二:Gradient Animations

现在,我们要写一个 Gradient Animations demo, 其最终效果是这样的: 实现步骤如下: 1. Drawing your first gradient 定义 gradient 的 start 和 end 位置: gradient 渐变,先由黑色到白色...

_浅墨_
07/25
0
0
巧用CSS的 Mask 滤镜

作者:冯永曜 在网页制作中使用CSS,这已是众所周知,而关于CSS滤镜使用的却介绍得不多。其实,0CSS的滤镜在Dreamweaver3中用起来也很方便,且能使文字产生一种类似图象的效果,但比起图片来...

晨曦之光
2012/03/09
126
0
慕课英雄第三人称射击游戏创作笔记

一、创建地形,布置地形 二、角色替身与动画片段 1.导入Teddy包,其自带了Teddy模型与动画片段 2.切割动画片段为walk,run,nod,shake等片段方便日后的使用 3.为模型配置Avatar人形骨骼 三、...

csuquan96
02/27
0
0
SVG之图形的引用user、剪切clip和蒙版mask

一、使用标签实现图形的引用   当我们在使用SVG绘制图形时,有时候会出现大量重复图形,这个时候我们就可以使用标签进行图形引用,相当于图形的克隆。在SVG文档内取得目标节点,并在别的地...

风之之
07/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

大数据学习有哪几个步骤

目前大数据行业异常火爆,不少人都对大数据充满了兴趣,其中有大部分人都从没接触过大数据,对于应该如何学习大数据一头雾水。大数据学习并不是高深莫测的,虽然它并没有多简单,但是通过努力...

董黎明
20分钟前
4
0
shell习题_3

1:监控httpd的进程;每隔10s检测一次服务器的httpd的进程数,如果大于500则自动重启httpd服务;并检测是否启动成功; 如果没有正常启动还需要再启动一次,最大不成功数超过五次立即发邮件给管理...

芬野de博客
21分钟前
3
0
Android 9.0 优势探讨

我们来谈论一下 Android。尽管 Android 只是一款内核经过修改的 Linux,但经过多年的发展,Android 开发者们(或许包括正在阅读这篇文章的你)已经为这个平台的演变做出了很多值得称道的贡献...

问题终结者
37分钟前
4
0
vue 组件使用中的一些细节点

细节一 基础例子 运行结果: 以上大家都懂,这边就不多说,回到代码里,有时候我们需要 tbody 里面每一行是一个子组件,那我们代码可以怎么写呢?我们可以这样写,定义一个全局组件,如下: ...

peakedness丶
44分钟前
2
0
vue 之 css module的使用方法

动手之前先配置项目,网上很多文章说需要下载css-loader插件,Vue中的vue-loader已经集成了 CSS Modules,因此删掉也能正常运行 在vue.config.js中添加如下配置 `css: {``loaderOptions: ...

前端小攻略
48分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部