1、首先从整体角度说一下:从实现动画的方法上来说,可以分为2个层次,第一个UIView方法,第二个是CGAffineTransform方法,第二个是coreAnimation的方法,他们分别属于UIKit、QuartzCore框架。动画的方法很多,不先分清是属于哪个层次或框架的方法容易搞混,而且有些长得也很像,比如CGAffineTransform和CATransition。而且不同层次的方法个性不一样,分清归类后比较容易知道在什么时候用什么。下面分别从这3个方面写一下实现动画的方法。
2、UIView方法:
从写法上来说,UIView的方法可以分为两类,即使用+ (void)beginAnimations:(NSString *)animationID context:(void *)context 结合 + (void)commitAnimations 。还是使用block块。从效果上来说应该没有区别,而且属性设置差不多,只是使用block需要注意避免循环引用。
以block方法为例,首先是最常用的+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
使用:
[UIView animateWithDuration:0.5 animations:^{
CGPoint imgCenter = _imgView.center;
_imgView.center = CGPointMake(imgCenter.x, imgCenter.y+50);
}];
_imgView是一个简单的图片View,这里的动画实现了图片的下移。很简单。和这个方法类似的还有3个,相比添加了一些控制动画的参数,
completion:后面是一个block这个是在动画执行结束时调用的,便于在动画执行结束后接着做处理。如果不使用block实现动画,需要使用下面3个方法结合使用来实现回调:
- + setAnimationDelegate: //指定下面两个方法的执行对象
- + setAnimationWillStartSelector: //指定在动画开始时调用的方法
- + setAnimationDidStopSelector:
使用UIView的方法可以使用几句代码实现复杂的动画,比如
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion方法,可以实现类似日历翻页效果。参数options是一个枚举,配置动画的一些属性,按效果分3部分,文档里面有意分割开了。第二部分是控制动画的速度行为,例如
UIViewAnimationOptionCurveEaseOut是指在动画结束的时候变化速度加快。第三部分是动画的效果,UIViewAnimationOptionTransitionFlipFromLeft是向左侧旋转翻转,UIViewAnimationOptionTransitionCurlUp是类似向上翻日历本一样的效果,UIViewAnimationOptionTransitionCrossDissolve是淡化当前的view然后逐渐变为目标view.但是有一点值得注意的,在flip和curl效果的时候,动画是作用在fromView的superView上面的。而且动画执行完后,fromView会从俯视图移除、释放掉,toView替代fromView原来的位置。
使用UIView的动画方法,会自动将写在一起的动画合并一起执行,比如
[UIView animateWithDuration:4.5 animations:^{
_imgView.alpha = 0.3;
CGPoint imgCenter = _imgView.center;
_imgView.center = CGPointMake(imgCenter.x, imgCenter.y+50);
}];
这里有透明度变化和位置变化两个动画,虽然透明变化的代码在前面,但是不会等这个动画执行完了在执行下一个,会通知执行这些动画,也就是说不需要自己去组装合并这些动画。如果希望顺序执行,可以分开写两个动画,但是ios7之后给了新的方法:
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;可以实现多个动画顺序执行并且可以很好控制单个动画的时间。
3、CGAffineTransform:
使用UIView方法实现动画,是通过更改目标View的属性来实现动画,好像是把原来一瞬间完成的事情拉长了,并且连续的执行。可以实现移动、缩放、渐变(透明度,颜色)等效果,但是想要实现旋转,貌似无法通过调节view的直观属性来实现,需要使用CGAffineTransform:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2];
CGAffineTransform transform =CGAffineTransformMakeRotation(M_PI);
[self.imgView setTransform:transform];
[UIView commitAnimations];
以上实现imgView旋转180度的效果,CGAffineTransform还是需要配合UIView的动画方法来使用,它提供了动画执行的方式。CGAffineTransform本身不是动画类也不提供动画方法,只是和UIView的动画方法结合比较简洁。CGAffineTransform有3种,即
Rotation旋转、Scale缩放和Translation移动。
4、coreAnimation类和方法:
coreAnimation的方法更底层,可以对动画进行更多的设定和控制。
首先是CAAnimation类,是动画抽象类,由它派生CAAnimationGroup和CAPropertyAnimation,CAAnimationGroup是合并多个动画时使用的组动画,类似于cocos2d里面的CCActionSequence的作用。CAPropertyAnimation又派生CAKeyframeAnimation和
CABasicAnimation。实现动画主要就是这两个类。CAKeyframeAnimation用来实现关键帧动画,CABasicAnimation则通过一个键值来制定动画类型。
(1)CAKeyframeAnimation:
首先什么是关键帧动画,百度百科http://baike.baidu.com/view/1336186.htm?fr=aladdin
在这里,我的理解是给定一系列关键的节点,这些节点指定了执行动画的view的状态,然后目标view在这些节点上连续的切换。
使用CAKeyframeAnimation很好的一个方面是用来实现一个路径动画,即指定某个view按特定路径进行运动,比如点击商品添加进购物车,需要商品划一道曲线然后落到购物车的位置。
CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef path = CGPathCreateMutable();
CGPoint center = self.imgView.center;
CGPathMoveToPoint(path, nil, center.x+20, center.y-20);
CGPathAddCurveToPoint(path, nil, 0, 0, 250, 600, 320, 500);
animation.path = path; //可以使用CGMutablePathRef来确定动画的路径,也可以使用values来确定,values是一系列关键的点;
animation.duration = 2.00;
animation.beginTime = 0; //用于多组动画播放的相对时间
animation.repeatCount = 0;
animation.removedOnCompletion = NO; //在动画结束后,是否将animation从layer上移除,如果移除,那么就会回到最初的状态,默认是YES;
// animation.autoreverses = YES;
animation.fillMode = kCAFillModeForwards; //上面设置了no,之后还要有这里设置一下,否则图片还是会回到最初的状态
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
//NSArray * keyTimes = @[@0,@0.1,@0.2,@0.3,@1];
//animation.keyTimes = keyTimes; //这个比较好用,就是每个点(动画里面的关键位置,比如values里面的每个点,在这个例子中就是rect的四角)所在的时间点(是时间点,不是所用的时间)
[self.imgView.layer addAnimation:animation forKey:@"position"]; //这是最后关键的一步,将动画加入到view的layer里面。
CGPathRelease(path);
以上是让self.imgView按一个曲线路径进行运动的动画实现,首先使用键值“position”来确定
CAKeyframeAnimation的类型,然后最重要的是给animation提供一个路径path,路径是CGMutablePathRef类型,通过CGPathCreateMutable()方法构建,而路径的具体内容和绘制曲线的方法几乎一致,了解quzrtz2D绘图之后就很容易理解路径的绘制,上面的例子就是一个贝塞尔曲线。因为路径可以任意绘制,所以想要什么样的动画运动路线都可以满足。
除了使用路径,也可以使用values来确定,values是一系列关键的点,执行动画的view会一次移动到给定的这些关键点,形成连续的移动动画。相对UIView的方法而言,如果是相对复杂多变的移动,使用CAKeyframeAnimation会简单很多。而使用values来指定运动路径时,keyTimes属性就起作用了,它也是一个数组,对应的指定了从动画开始到相应点的时间。比如NSArray * keyTimes = @[@0,@0.1,@0.2,@0.3,@1];那么运动到第一个点的时间是总时间*0.1,运动到第二个点时的时间是总时间*0.2。
(2)CABasicAnimation:
CABasicAnimation * rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotationAnimation.fromValue = [NSNumber numberWithFloat:0];
rotationAnimation.toValue = [NSNumber numberWithFloat:2 * M_PI];
rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.duration =2.0;
rotationAnimation.repeatCount = 0;
//rotationAnimation.autoreverses = YES;
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[rotationAnimation setDelegate:self];
[self.imgView.layer addAnimation:rotationAnimation forKey:nil];
同样使用键值和方法 animationWithKeyPath:来构建动画对象并指定动画的类型。CABasicAnimation基本上是通过指定fromValue和toValue来确定动画执行的变化的。比如上面的例子,是执行旋转动画,然后指定的开始和结束值就是角度,所以
rotationAnimation.fromValue = [NSNumber numberWithFloat:0];
rotationAnimation.toValue = [NSNumber numberWithFloat:2 * M_PI];
这样动画就会瞬间切换到fromValue的状态,然后动画形式变化到tovalue状态。
所以从使用角度来说,知道使用什么键值来指定CABasicAnimation的类型以及使用什么样对应的fromValue和toValue是关键。
键值有这些:
transform.scale 缩放
bounds 大小
transform.rotation 旋转
opacity 透明度变化
shadowOffset 阴影范围
cornerRadius 圆角的大小
contents 内容变化,可以使用它以渐变方式替换imageView的图片
然后,CAAnimation可以指定委托对象,但是这里的委托没有协议需要继承,只要指定了对象就可以响应动画的委托方法,便于在动画的执行过程中进行响应控制。
最后,还有许多没有研究,以后有了新东西在添加。