常见的动画实现方式
先祭上一张大图,说明两种常见动画的层次关系
- UIView层面上的动画
- CoreAnimation的Layer层动画
UIView层的动画
第一种就是常见的我们经常使用的UIView的闭包动画,记得使用这个动画,内部的两个控件要在同一个View上,不然会Crash.
//UIView层面的自定义动画1
[UIView animateWithDuration:0.5 animations:^{ }];
第二种是提交动画,由两句话控制,类似C序言的过程语言
//UIView层面的系统动画2
[UIView beginAnimations:@"animationID" context:nil];//动画开始
//设置动画属性开始
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:customView cache:YES];
//设置动画属性结束
[UIView commitAnimations];//动画提交
这里会用到几个概念
- animationID:这个是你每个动画的名字,是自定义的,在以后拦截动画的时候会用到
- context: 自定义的想和动画交互的数据
在设置好了以上数据后,就可以通过commitAnimations让动画开始执行.但是和方法1很大的不同是,这样的动画设置可以同时提交好多个,而且有系统的做好的动画效果.
系统做好的转场效果
有一个函数**setAnimationTransition:forView:cache:**是专门来控制转场效果,官方提供的转场是个枚举,而且这个函数只能在每个动画中有效一次.
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
//.h
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
// current limitation - only one per begin/commit block
提交多个和拦截参数
先来看下官方文档和头文件
You can nest sets of animations (by calling this method again before committing a previous set of animations) as needed.
Nesting animations groups them together and allows you to set different animation options for the nested group.
If you install a start or stop selector using the setAnimationWillStartSelector: or setAnimationDidStopSelector: method,
the values you specify for the animationID and context parameters are passed to your selectors at runtime.
You can use these parameters to pass additional information to those selectors.
你可以通过begin/commit执行多个动画,但是头文件中说了,这两个必须成对出现
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;
// additional context info passed to will start/did stop selectors. begin/commit can be nested
+ (void)commitAnimations;
// starts up any animations when the top level animation is commited必须在上一个动画commit后才行
而动画的拦截方法就是**setAnimationWillStartSelector:和setAnimationDidStopSelector:**两个代理方法,可以在里面获取到ID和context.
使用CATransition在Layer层上的动画
在Layer层的动画的上有很多,可以参考官方文档Core Animation Reference Collection.这里通过添加CATransition对象来举例添加动画
CATransition *animation = [CATransition animation];
animation.duration = 0.5f; //动画时长
animation.type = @"cube"; //过度效果
animation.subtype = @"formLeft"; //过渡方向
[self.view.layer addAnimation:animation forKey:@"animationID"];
CATransition本身分为type和subType两种,是通过字符串来传递属性的
/* The name of the transition. Current legal transition types include
* `fade', `moveIn', `push' and `reveal'. Defaults to `fade'. */
@property(copy) NSString *type;
/* An optional subtype for the transition. E.g. used to specify the
* transition direction for motion-based transitions, in which case
* the legal values are `fromLeft', `fromRight', `fromTop' and
* `fromBottom'. */
@property(nullable, copy) NSString *subtype;
根据官方文档查询他们的常量字符串是
//type
NSString * const kCATransitionFade;
NSString * const kCATransitionMoveIn;
NSString * const kCATransitionPush;
NSString * const kCATransitionReveal;
//subType
NSString * const kCATransitionFromRight;
NSString * const kCATransitionFromLeft;
NSString * const kCATransitionFromTop;
NSString * const kCATransitionFromBottom;
但是不知道为什么网上流传着一份全部的动画效果,可以通过字符串调用实现,比如例子中的”cube”动画就不在官方文档里,但是确实可以实现.
/* 过渡效果
fade //交叉淡化过渡(不支持过渡方向)
push //新视图把旧视图推出去
moveIn //新视图移到旧视图上面
reveal //将旧视图移开,显示下面的新视图
cube //立方体翻滚效果
oglFlip //上下左右翻转效果
suckEffect //收缩效果,如一块布被抽走(不支持过渡方向)
rippleEffect //滴水效果(不支持过渡方向)
pageCurl //向上翻页效果
pageUnCurl //向下翻页效果
cameraIrisHollowOpen //相机镜头打开效果(不支持过渡方向)
cameraIrisHollowClose //相机镜头关上效果(不支持过渡方向)
*/
/* 过渡方向
fromRight;
fromLeft;
fromTop;
fromBottom;
*/
UIView层和Layer层的动画混用
把一个Image放在一个View的Layer上来放大的时候,如果用UIView来做,图片不会太多的失真和闪烁的效果,但是用Core Animation来做失真和闪烁现象会很严重,效果很不好。为了解决这个问题,只要把各自的动画放在一起就可以了.
[imageLayer addAnimation:[self animationOpen] forKey:@"Open"];
[UIView beginAnimations:@"zoom out" context:nil];
[UIView setAnimationDuration:1.f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
cover.transform = CGAffineTransformMakeScale(5.5,5.5);
cover.center = CGPointMake(629, 384);
[UIView commitAnimations];
- (CAAnimation *)animationOpen
{
CABasicAnimation *animationOpen
= [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
animationOpen.duration = 1;
animationOpen.autoreverses = NO;
animationOpen.delegate = self; //然后执行真正地打开书的内容
animationOpen.removedOnCompletion = NO;
animationOpen.fillMode = kCAFillModeForwards;
animationOpen.fromValue = [NSNumber numberWithFloat:-M_PI/5];
animationOpen.toValue = [NSNumber numberWithFloat:-M_PI/1.5];
return animationOpen;
}