从CoreAnimation到Facebook‘s Pop(1)
相信所有开发者在开发阶段都会接触到动画,简单的从UIView层的动画一直到layer层的动画,抑或通过重绘实现的动画。在恰当场景使用合适的动画不仅可以让你的app交互更加新奇有趣,而且能够体现出作者的实力。实在是居家旅行的必备。
其实最理想的动画应该是专门负责交互的设计师使用Quartz Composer或者AE之类的设计工具,设计完之后告诉你时间节点,动画样式之类的数据,然后你直接利用代码转换,然后据我所知,国内的大部分公司(至少9成)是没有这样的流程的,大部分动画都靠凑出来。可能是工程师通过一次次调校代码的参数调出来的。
国内的app开发者可能不是太重视这方面的开发,所以很少有给我那种第一次见到paper(facebook出品)或者是Taasky,City Guides那种震撼感觉的。
![这是Taasky的](http://cdn3.raywenderlich.com/wp-content/uploads/2014/05/TaaskyFoldingNavAndNew.gif)
![这是国家地理杂志出的City guide](http://cdn4.raywenderlich.com/wp-content/uploads/2014/05/CityGuidesStatistics.gif)
![这是Paper](http://cdn1.raywenderlich.com/wp-content/uploads/2014/05/PaperSections.gif)
这个系列的博客主要讲的是Layer层动画的实现,因为View层的动画实际上并不难掌握,相信大家也都使用的很熟练了。
每个view都有一个layer,layer主要负责渲染,view只是在layer的基础上增加了Event Handle一类的东西,实际上你调整view的frame也好,调backgroundcolor也罢,这类负责展示的属性实际上都是在调整layer的对应属性。动画无非就是layer层的再次渲染。
这篇博客将通过这个例子告诉大家CABasicanimation
的基本用法.
![我们的目标](http://m1.img.srcdd.com/farm5/d/2014/1221/12/BDA3ECAE3C126E71EF72B18212E166E2_ORIG_346_693.gif)
看到别人的交互第一个想法应该是拆解,因为一个优秀的动画肯定不是由一个单元的效果,或者单一的时间线(timingfuntion)组成的。肯定是由多种不同的效果组成。
我们来试着拆解一下上图的圆球动画效果。
- 第一步最明显的肯定是小圆从小变到大。
- 那么我们应该可以想到是做了makescale,而且在做scale之前要先修改view的cornerRadius以使这个view变成一个圆形。
-
然后最明显的变化就是这个圆变成了椭圆。可能这个地方会有人断了思路,仔细想想其实不难。makescale需要传参数。
CATransform3DMakeScale(0.1, 0.1, 1)
4.这三个参数分别代表在x,y,z轴压缩的比例,当x,y轴压缩比率相同的情况下view的宽高缩放比例相同,那么只改变Y轴缩放比例,让Y轴缩放比例大于X轴缩放比例那么一个圆不就变成了椭圆么。
5.想到这其实第二个动画的实现也呼之欲出。我们只需要在小圆同比率变大到一定程度之后,只改变Y 轴的放大比率就行了。
我们先实现第一个拆解的动画,就是X,Y轴同比率缩放。
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.duration = 3.;
animation.fromValue = @(0.1);
animation.toValue = @(1.);
return animation;
这个地方我想多说几句的是这个叫做animationWithKeyPath
的东西。这个keyPath到底是什么?
一句话,就是CALayer的所有属性。如图展示了一部分属性
![CALayer的一部分属性](http://m1.img.srcdd.com/farm4/d/2014/1221/10/872DE7E937718B9B2FD6328394352A72_B800_2400_800_1026.png)
这样,你们可以自己写一个CABasicAnimation 然后在keypath里分别填入下面的属性,自己试试效果。(连shadowColor都可以用basicanimation做动画哦!)
我们来看看第一个拆解动画的效果。
![](http://m3.img.srcdd.com/farm4/d/2014/1221/12/65E943FD1D77130D4E92387CD44D135C_ORIG_391_693.gif)
然后第二个拆解动画,我们只改变Y轴压缩率。
- (CABasicAnimation *)createScaleYAnimation
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
animation.duration = 3.;
animation.fromValue = @(1);
animation.toValue = @(2.);
return animation;
}
效果如图所示:
![](http://m2.img.srcdd.com/farm5/d/2014/1221/12/582DA8B4182F229A7A7E5C620F5EC899_ORIG_391_693.gif)
那么问题来了,我们只是单独的实现了两个动画,怎么才能把他组合起来呢,而且这两个动画是有先后次序的。
很简单,苹果早已为我们准备了这个叫做CAGroupAnimation
的东西。他可以组合多个CAAnimation,并且分配他们的开始时间和动画时长。
代码如下。
- (CAAnimationGroup *)createGroupAnimation
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.duration = 3.;
animation.fromValue = @(0.1);
animation.toValue = @(1.);
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
animation2.duration = 3.;
animation2.fromValue = @(1);
animation2.toValue = @(2.);
animation2.beginTime = 3.;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 6.;
group.animations = @[animation,animation2];
return group;
}
这里唯一需要解释的可能就是animation2比animation多了一个beginTime,很简单,beginTime就是动画开始的时间,既然第一个动画持续时间是3秒,那么第二个动画应当在第一个动画结束的时候执行,那么就是第三3秒钟开始了。(当然,你也可以让两个动画同时执行,比如把beginTime设置为2,那么当第一个动画执行到2秒还没完的时候第二个动画就开始执行了。)
我们看看效果。
![](http://m3.img.srcdd.com/farm5/d/2014/1221/13/7E392DC215752B9380C558F6BF3B69BA_ORIG_391_693.gif)
现在我们完成了基本的动画,现在唯一的问题就是把动画和tableview的offset联系起来。直接贴代码。你们感受一下。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(@"offset is %@",NSStringFromCGPoint(_mTableView.contentOffset));
CGFloat delta = 8./-150;
if (_mTableView.contentOffset.y>-150) {
[animationView setAnimationProgress:(_mTableView.contentOffset.y*delta)];
}else
{
[animationView setAnimationProgress:8.];
}
}
然后我们最后的效果如下。
![](http://m3.img.srcdd.com/farm4/d/2014/1221/12/C34AE5E285AC5651B69516A0A7B2BA2A_ORIG_391_693.gif)
最后放上我们的github地址: https://github.com/pingguo-zangqilong/CoreAnimationLesson1