版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 网址:谈谈iOS中粘性动画以及果冻效果的实现在最近做个一个自定义PageControlKYAnimatedPageControl中,我实现了CALayer的形变动画以及CALayer的弹性动画,效果先过目:先做个提纲:第一个分享的主题是“如何让CALayer发生形变”,这个技术在我之前一个项目 KYCuteView 中有涉及,也写了篇简短的实现原理博文。今天再举一个例子。之前我也做过类似果冻效果的弹性动画,比如这个项目 KYGooeyMenu。用到的核心技术是CAKeyframeAnimation,然后设置几个不同状态的关键帧,就能初步达到这种弹性效果。但是,毕竟只有几个关键帧,而且是需要手
2、动计算,不精确不说,动画也不够细腻,毕竟你不可能手动创建60个关键帧。所以,今天的第二个主题是 “如何用阻尼振动函数创建出60个关键帧”,从而实现CALayer产生类似UIView animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion 的弹性动画。正文。如何让CALayer发生形变?关键技术很简单:你需要用多条贝塞尔曲线 “拼” 出这个Layer。之所以这样做的原因不言而喻,因为这样方便我们发生形变。比如 KYAnimatedPageControl
3、 中的这个小球,其实它是这么被画出来的:小球是由弧AB、弧BC、弧CD、弧DA 四段组成,其中每段弧都绑定两个控制点:弧AB 绑定的是 C1 、 C2;弧BC 绑定的是 C3 、 C4 .如何表达各个点?首先,A、B、C、D是四个动点,控制他们动的变量是ScrollView的contentOffset.x。我们可以在-(void)scrollViewDidScroll:(UIScrollView *)scrollView中实时获取这个变量,并把它转换成一个控制在 01 的系数,取名为factor。1_factor = MIN(1, MAX(0, (ABS(scrollView.contentO
4、ffset.x - self.lastContentOffset) / scrollView.frame.size.width);假设A、B、C、D的最大变化距离为小球直径的2/5。那么结合这个01的系数,我们可以得出A、B、C、D的真实变化距离 extra 为:extra = (self.width * 2 / 5) * factor。当factor = 1时,达到最大形变状态,此时四个点的变化距离均为(self.width * 2 / 5)。注意:根据滑动方向,我们还要根据是B点移动还是D点移动。1. CGPoint pointA = CGPointMake(
5、rectCenter.x ,self.currentRect.origin.y + extra); 2. CGPoint pointB = CGPointMake(self.scrollDirection = ScrollDirectionLeft ? rectCenter.x + self.currentRect.size.width/2 : rectCenter.x + self.currentRect.size.widt
6、h/2 + extra*2 ,rectCenter.y); 3. CGPoint pointC = CGPointMake(rectCenter.x ,rectCenter.y + self.currentRect.size.height/2 - extra); 4. CGPoint pointD = CGPointMake(self.scrollDirection = ScrollDirectionLeft
7、0;? self.currentRect.origin.x - extra*2 : self.currentRect.origin.x, rectCenter.y); 然后是控制点:关键是要知道上图中A-C1 、B-C2、B-C3、C-C4.这些水平和垂直虚线的长度,命名为offSet。经过多次尝试,我得出的结论是:当offSet设置为 直径除以3.6 的时候,弧线能完美地贴合成圆弧。我隐约感觉这个 3.6 是必然,貌似和360度有某种关系,或许通过演算能得出 3.6 这个值的必然性,但我没有尝试。因此,各个控制点的坐标:1
8、. CGPoint c1 = CGPointMake(pointA.x + offset, pointA.y); 2. CGPoint c2 = CGPointMake(pointB.x, pointB.y - offset); 3. CGPoint c3 = CGPointMake(pointB.x, pointB.y + offset); 4. CGPoint c4
9、0;= CGPointMake(pointC.x + offset, pointC.y); 5. CGPoint c5 = CGPointMake(pointC.x - offset, pointC.y); 6. CGPoint c6 = CGPointMake(pointD.x, pointD.y + offset); 7. CGPoint c7 = CGPointMake(
10、pointD.x, pointD.y - offset); 8. CGPoint c8 = CGPointMake(pointA.x - offset, pointA.y); 有了终点和控制点,就可以用UIBezierPath 中提供的方法 - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; 画线段了。重载
11、CALayer的- (void)drawInContext:(CGContextRef)ctx;方法,在里面画图案:1. - (void)drawInContext:(CGContextRef)ctx 2. ./在这里计算每个点的坐标 3. UIBezierPath* ovalPath = UIBezierPath bezierPath; 4. ovalPath moveToPoint: pointA; 5. ovalPath addCurveToPoint:pointB
12、160;controlPoint1:c1 controlPoint2:c2; 6. ovalPath addCurveToPoint:pointC controlPoint1:c3 controlPoint2:c4; 7. ovalPath addCurveToPoint:pointD controlPoint1:c5 controlPoint2:c6; 8. ovalPath addCurveToPoint:pointA controlPoint1:c7 cont
13、rolPoint2:c8; 9. ovalPath closePath; 10. CGContextAddPath(ctx, ovalPath.CGPath); 11. CGContextSetFillColorWithColor(ctx, self.indicatorColor.CGColor); 12. CGContextFillPath(ctx); 13. 现在,当你滑动ScrollView的时候,小球就会形变了。如何用阻尼振动函数创建出60个关键帧?上面的例子中,有个很重要的因素,就是Scrol
14、lView中的contentOffset.x这个变量,没有这个输入,那接下来什么都不会发生。但想要获得这个变量,是需要用户触摸、滑动去交互产生的。在某个动画中用户是没有直接的交互输入的,比如当手指离开之后,要让这个小球以果冻效果弹回初始状态,这个过程手指已经离开屏幕,也就没有了输入,那么用上面的方法肯定行不通,所以,我们可以用CAAnimation.我们知道,iOS7中苹果在 UIView(UIViewAnimationWithBlocks) 加入了一个新的制作弹性动画的工厂方法:1. + (void)animateWithDuration:(NSTimeInterval)durat
15、ion delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void ()(void)animations completion:(void ()(BOOL finished)completion NS_AVAILABLE
16、_IOS(7_0); 但是没有直接的关于弹性的 CAAnimation 子类,类似CABasicAnimation或CAKeyframeAnimation 来直接给CALayer添加动画。好消息是iOS9中添加了公开的 CASpringAnimation。但是出于兼容低版本以及对知识探求的角度,我们可以了解一下如何手动给CALayer创建一个弹性动画。在开始之前需要复习一下高中物理知识 阻尼振动,你可以点击高亮字体的链接稍微复习一下。 根据维基百科,我们可以得到如下振动函数通式:当然这只是一个通式,我们需要让 图像过(0,0),并且最后衰减到1 。我们可以让原图像先绕X轴翻
17、转180度,也就是加一个负号。然后沿y轴向上平移一个单位。所以稍加变形可以得到如下函数:想看函数的图像?没问题,推荐一个在线查看函数图象的网站 Desmos ,把这段公式 1-left(e-5xcdot cos (30x)right) 复制粘帖进去就可以看到图像。改进后的函数图像是这样的:完美满足了我们 图形过(0,0),震荡衰减到1 的要求。其中式子中的 5 相当于阻尼系数,数值越小幅度越大;式子中的 30 相当于震荡频率 ,数值越大震荡次数越多。接下来就需要转换成代码。总体思路是创建60帧关键帧(因为屏幕的最高刷新频率就是60FPS),然后把这60帧数据赋值给 CAKeyframeAnim
18、ation 的 values 属性。用以下代码生成60帧后保存到一个数组并返回它,其中/1就是利用刚才的公式创建60个数值:1. +(NSMutableArray *) animationValues:(id)fromValue toValue:(id)toValue usingSpringWithDamping:(CGFloat)damping initialSpringVelocity:(CGFloat)velocity duration:(CGFloat)duration 2. /60个关键帧 3. NSIn
19、teger numOfPoints = duration * 60; 4. NSMutableArray *values = NSMutableArray arrayWithCapacity:numOfPoints; 5. for (NSInteger i = 0; i < numOfPoints; i+) 6. values addObject:(0.0);
20、;7. 8. /差值 9. CGFloat d_value = toValue floatValue - fromValue floatValue; 10. for (NSInteger point = 0; point CGFloat x = (CGFloat)point / (CGFloat)numOfPoints; 11. CGFloat value
21、;= toValue floatValue - d_value * (pow(M_E, -damping * x) * cos(velocity * x); /1 y = 1-e-5x * cos(30x) 12. valuespoint = (value); 13. 14. return values; 15. 接下来创建
22、一个对外的类方法,并返回一个 CAKeyframeAnimation :1. +(CAKeyframeAnimation *)createSpring:(NSString *)keypath duration:(CFTimeInterval)duration usingSpringWithDamping:(CGFloat)damping initialSpringVelocity:(CGFloat)velocity fromValue:(id)fromValue toValue:(id)toValue 2. CAK
23、eyframeAnimation *anim = CAKeyframeAnimation animationWithKeyPath:keypath; 3. NSMutableArray *values = KYSpringLayerAnimation animationValues:fromValue toValue:toValue usingSpringWithDamping:damping * dampingFactor initialSpringVe
24、locity:velocity * velocityFactor duration:duration; 4. anim.values = values; 5. anim.duration = duration; 6. return anim; 7. 另一个关键以上,我们创建了 CAKeyframeAnimation 。但是这些values到底是对谁起作用的呢?如果你熟悉CoreAnimation的话,没错,是对传入的keypath起作用。而这些keypath其实就
25、是CALayer中的属性property。比如,之所以当传入的keypath为transform.rotation.x时CAKeyframeAnimation会让layer发生旋转,就是因为CAKeyframeAnimation发现CALayer中有这么个属性叫transform,于是动画就发生了。现在我们需要改变的是主题一中的那个factor变量,所以,很自然地想到,我们可以给CALayer补充一个属性名为factor就行了,这样CAKeyframeAnimation加到layer上时发现layer有这个factor属性,就会把60帧不同的values赋值给factor。当然我们要把from
26、Value和toValue控制在01:1. CAKeyframeAnimation *anim = KYSpringLayerAnimation createSpring:"factor" duration:0.8 usingSpringWithDamping:0.5 initialSpringVelocity:3 fromValue:(1) toValue:(0); 2. self.factor = 0; 3. self addAnimation:anim forKey:"restoreAnimation" 最后一步,虽然CAKeyframeAnimation实时地去改变了我们想要的factor,但我们还得通知屏幕刷新,这样才能看到动画。1. +(BOOL)needsDisplayForKey:(NSString *)key 2. if (key isEqual:"factor") 3. return YES; 4.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 房屋租赁代理协议范本2024年
- 2024届广东省清远市第三中学高三下第六次周考数学试题
- 二手房家具买卖细则协议2024
- 2024届广东省广州市执信、广雅、六中高三下学期第二次调研测试数学试题
- 出资合同范本
- 影视拍摄合同范本
- 2024专业咨询服务劳务协议范本
- 农业顾问 合同范本
- 八年级语文下册第4单元《孔乙己》说课稿
- 网签版购房合同范本
- 电力工程施工售后保障方案
- 2024年小学心理咨询室管理制度(五篇)
- 第16讲 国家出路的探索与挽救民族危亡的斗争 课件高三统编版(2019)必修中外历史纲要上一轮复习
- 机器学习 课件 第10、11章 人工神经网络、强化学习
- 北京市人民大学附属中学2025届高二生物第一学期期末学业水平测试试题含解析
- 书籍小兵张嘎课件
- 氢气中卤化物、甲酸的测定 离子色谱法-编制说明
- 初中《学宪法讲宪法》第八个国家宪法日主题教育课件
- 2024医疗机构重大事故隐患判定清单(试行)学习课件
- 《抗心律失常药物临床应用中国专家共识2023》解读
- 四年级家长会(完美版)
评论
0/150
提交评论