iOS 自定义下拉线条动画

本文摘录自A GUIDE TO IOS ANIMATION,中文名:《Kitten 的 iOS 动画学习手册》。这是一本非常有趣地介绍 iOS 动画的交互式电子书,提供生动的可交互式元素、视频以及精心制作的配图,让你在前所未有的阅读体验中学到干货。购买方式请看我的置顶微博

这是本章的第二个 demo,下面这个案例中,我把线条动画和数学知识结合在了一起。通过这个案例,可以很好地向你展示如何自己归纳出一个数学公式,并把它用到一个自定义动画中。

首先,我们还是先看最终效果 :

OK,可以看到随着手指在屏幕上滑动距离的改变,线条一开始逐渐靠拢,到达一定位置后开始弯曲,最终合并成了一个圆。顺便一提,我已经把这个动画封装到了一个上拉、下拉刷新的控件中,并且用在了大象公会这款独立开发的 App 中。 你可以提前下载下来一睹实际效果。

下面讲讲我是怎么思考这个动画的。首先,最终控制这个动画进度的是一个CALayer内部的自定义的属性:

@property(nonatomic,assign)CGFloatprogress;

无论你是通过手指滑动产生偏移量,还是滑动 UISlider 改变一个数值,最终都将转化到这个属性的改变。然后,在这个属性的 setter 方法里,我们让 layer 去实时地重绘,就像这样:

-(void)setProgress:(CGFloat)progress{self.curveLayer.progress= progress;    [self.curveLayersetNeedsDisplay];}

至于重绘的算法,属于细节上要考虑的事了。我们做一个动画的步骤都是先考虑宏观,再去考虑细节上的实现。就像开发一个 App 一样,一开始肯定是先考虑架构,再去往这个框架里添砖加瓦,修修补补。现在,我们对这个动画的整体思路已经清楚了,下面开始深入到细节去思考具体算法的实现。我把这个动画分成了两个阶段:0~0.5 和 0.5~1.0。 这是什么意思?

做动画还是那句话 ——「善于分解」。我们先看前半程,也就是 progress 从一开始的 0 运动到中间状态 0.5 的这一个阶段。这一个阶段两条线段分别从上方和下方两个方向向中间运动,直到接触到中线为止。这一阶段的画线算法非常简单,只要能实时获得 A,B 两点的坐标,剩下用 UIBezierPath 的moveToPoint,addLineToPoint就完事了。所以,问题转换成了求 A,B 两点运动的公式(其实只要求出一点,另一点无非就相差了一个线段长度 h)。请看演示动画(注:在电子书中是有交互动画的,但因为现在是以文章的形式呈现,所以我只能通过图片的方式向你展示)

其实你只要愿意动笔在纸上尝试推演一番,并不难求得这两个点的运动公式:

yA = H/2 + h + (1-2*progress) * (H/2 - h)

yB = H/2 + (1-2*progress) * (H/2 - h)

接下来是动画的第二阶段 0.5~1.0。这个阶段有些许复杂:「B 点保持不动,A 点继续运动到 B 的位置,同时,在顶部根据当前的进度再画出圆弧」。视觉上给人的感觉就好像尾巴在逐渐缩短,头部在慢慢弯曲。同样的,我只能以图片的形式向你展示。

在这个过程中,我们不难先求得 A 点的坐标是:

yA = H/2 + h - h*(progress - 0.5) *2

比较麻烦的是这个圆弧该怎么画?答案是可以用 UIBezierPath 中提供的- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);这个方法绘制出圆弧。具体思路是:以CGPointMake(self.frame.size.width/2,self.frame.size.height/2)为圆心,10为半径,按顺时针方向,从M_PI(90°)的起始角度,画到2*M_PI的结束角度。

关于- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;方法的解释:如果设置开始角度均为 0 ,结束角度均为 π。那么设置 clockwise(顺时针) 为 YES 时,画出的是下半段圆弧;反之, 设置 clockwise(顺时针) 为 NO 时,画出的是上半段圆弧;

以上,我们只完成了一条线段的整个过程。同理,也能获得另一条线段的绘制算法。最后,别忘了线段顶端还有个箭头。绘制箭头的算法 Gallery 4.1:我们以 B 点作为箭头的起始起点,斜向左下方 30° 角延长 3 个单位。弯曲之后也同理,只需要额外加上线段转过的角度即可。

相应的代码就是:

[arrowPath moveToPoint:pointB];[arrowPath addLineToPoint:CGPointMake(pointB.x-3*(cosf(Degree)), pointB.y+3*(sinf(Degree)))];[curvePath1 appendPath:arrowPath];

OK,这一个 demo 的分析到这里就结束了。完整代码可以在本书对应的Github Repo中下载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容