原文参考:http://www.cnblogs.com/kenshincui/p/3972100.html#uiviewanimation
coreAnimation官方资料翻译: http://www.cnblogs.com/pengyingh/articles/2396032.html
IOS动画中的枚举UIViewAnimationOptions
粒子动画 CAEmitterLayer和CAEmitterCell
iOS复杂动画之抽丝剥茧(Objective-C & Swift)
概览
在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画、关键帧动画、动画组、转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等。在今天的文章里您可以看到动画操作在iOS中是如何简单和高效,很多原来想做但是苦于没有思路的动画在iOS中将变得越发简单:
- CALayer
- CALayer简介
- CALayer常用属性
- CALayer绘图
- Core Animation
- 基础动画
- 关键帧动画
- 动画组
- 转场动画
- 逐帧动画
- UIView动画封装
- 基础动画
- 关键帧动画
- 转场动画
CALayer
在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮,一个文本标签,一个文本输入框,一个图标等等,这些都是UIView.
UIView之所以能显示在屏幕上,完全是因为它内部的一个图层.
UIView的显示原理
在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个图层.
1
|
@property(nonatomic,readonly,retain) CALayer *layer;
|
当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有的内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView的显示.
换句话说,UIView本身不具备显示的功能,是它内部的层才有显示功能.
CALayer的基本使用
通过操作CALayer对象,可以很方便的调整UIView的一些外观属性,比如阴影, 圆角大小, 边框宽度和颜色等.还可以给图层添加动画来实现一些比较炫酷的效果.
CALayer的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 宽度和高度
@property CGRect bounds;
// 位置(默认指中点,具体由anchorPoint决定)
@property CGPoint position;
// 锚点(x,y的范围都是0-1),决定了position的含义
@property CGPoint anchorPoint;
// 背景颜色(CGColorRef类型)
@property CGColorRef backgroundColor;
// 形变属性
@property CATransform3D transform;
// 边框颜色(CGColorRef类型)
@property CGColorRef borderColor;
// 边框宽度
@property CGFloat borderWidth;
// 圆角半径
@property CGColorRef borderColor;
//内容(比如设置为图片CGImageRef)
@property(retain) id contents;
|
关于CALayer
首先:
CALayer 是定义在 QuartzCore 框架中的;
CGImageRef, CGColorRe f两种数据类型是定义在在 CoreGraphics 框架中的;
UIColor, UIImage 是定义在 UIKit 框架中.
其次:
QuartzCore 和 CoreGraphics 框架是可以跨平台使用的,在iOS和Mac OS X上都能使用 ;
UIKit只能使用在iOS中.
为了保证可移植性,QuartzCore不能使用UIImage, UIColor,只能使用CGImageRef, CGColorRef.
UIView和CALayer的选择
通过CALayer, 就能做出跟UIImageView一样的界面效果. 既然CALayer和UIView都能实现相同的显示效果,那究竟该选择谁好呢?
对比CALayer, UIView多了一个事件处理功能. 也就是说,CALayer不能处理用户的触摸事件,而UIView可以.
所以,如果显示出来的东西需要跟用户进行交互的话, 用UIView; 如果不需要跟用户进行交互, 用UIView或者CALayer都可以;当然,CALayer的性能更高一些, 因为它少了事件处理功能, 更加轻量级.
position和anchorPoint
CALayer有两个非常重要的属性:position和anchorPoint .
1
|
@property CGPoint position;
|
用来设置CALayer在父层中的位置,以父层的左上角为原点(0,0).
1
|
@property CGPoint anchorPoint;
|
anchorPoint称为:"定位点" 或 "锚点";
决定了CALayer身上的哪个点会在position属性所指的位置,以自己的左上角为原点(0,0);
anchorPoint的 x ,y 的取值范围都是 0 ~ 1, 默认值为(0.5 ,0.5).
隐式动画
每一个UIView内部都默认关联一个CALayer, 我们可以称这个layer为Root Layer(根层).
所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动画.
什么是隐式动画 ?
当对非Root Layer的部分属性进行修改时, 默认会自动产生一些动画效果.而这些属性称为Animatable Properties(可动画属性).
列举几个常见的Animatable Properties(可动画属性);
bounds : 用于设置CALayer的宽度和高度 ; 修改这个值, 会产生缩放动画 .
backgroundColor : 用于设置CALayer的背景色 ;修改这个属性会产生背景色的渐变动画 .
position : 用于设置CALayer的位置 ;修改这个属性会产生平移动画 .
可以通过动画事务(CATransaction)关闭默认的隐式动画效果;
1
2
3
4
|
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];
|
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _parentView=[[UIView alloc]initWithFrame:CGRectMake(40, 40, 160, 240)]; _parentView.backgroundColor=[UIColor blueColor]; _imageView01=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 160, 240)]; _imageView01.image=[UIImage imageNamed:@"17_1.jpg"]; _imageView02=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 160, 240)]; _imageView02.image=[UIImage imageNamed:@"17_2.jpg"]; [_parentView addSubview:_imageView01]; [_parentView addSubview:_imageView02]; [self.view addSubview:_parentView]; UIBarButtonItem *btnNext=[[UIBarButtonItem alloc]initWithTitle:@"下一级" style:UIBarButtonItemStyleBordered target:self action:@selector(pressNxet)]; self.navigationItem.rightBarButtonItem=btnNext; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { CATransition *tranAnim=[[CATransition alloc]init]; tranAnim.duration=2.0f; //"cube", suckEffect, oglFlip, rippleEffect, pageCurl, pageUnCurl, cameraIrisHollowOpen, cameraIrisHollowClose //设置动画类型,淡出动画 tranAnim.type=@"cameraIrisHollowClose"; //设置动画子类型出现的位置,从左侧出现 // kCATransitionFromLeft // kCATransitionFromRight // kCATransitionFromTop //kCATransitionFromBottom tranAnim.subtype=kCATransitionFromBottom; //设置动画代理 tranAnim.delegate=nil; //将动画添加到父视图的层中 [_parentView.layer addAnimation:tranAnim forKey:@"anim"]; //获得子时图一二的索引 NSInteger index01=[_parentView.subviews indexOfObject:_imageView01]; NSInteger index02=[_parentView.subviews indexOfObject:_imageView02]; //交换两个子时图的索引的位置 [_parentView exchangeSubviewAtIndex:index01 withSubviewAtIndex:index02]; } -(void)pressNxet { //"cube", suckEffect, oglFlip, rippleEffect, pageCurl, pageUnCurl, cameraIrisHollowOpen, cameraIrisHollowClose CATransition*tranAnim=[CATransition animation]; tranAnim.duration=1.0f; tranAnim.type=kCATransitionMoveIn; [self.navigationController.view.layer addAnimation:tranAnim forKey:@"ripplecuEffect"]; tranAnim.subtype=kCATransitionFromLeft; VCSecond*second=[[VCSecond alloc]init]; [self.navigationController pushViewController:second animated:YES]; }
animation.duration = 0.3;
animation.type = @"cube";
animation.subtype = kCATransitionFromLeft;
//animation.type = kCATransitionFade;
[[self.tableView layer] addAnimation:animation forKey:@"myAnimation"];
参数说明:
setType:可以返回四种类型:
kCATransitionFade淡出kCATransitionFade淡出kCATransitionMoveIn覆盖原图kCATransitionPush推出kCATransitionReveal底部显出来setSubtype:也可以有四种类型:
kCATransitionFromRight;kCATransitionFromLeft(默认值)kCATransitionFromTop;kCATransitionFromBottom[animation setType:@"suckEffect"];
这里的suckEffect就是效果名称,可以用的效果主要有:
pageCurl 向上翻一页pageUnCurl 向下翻一页rippleEffect 滴水效果suckEffect 收缩效果,如一块布被抽走cube 立方体效果oglFlip 上下翻转效果 animation.fillMode = kCAFillModeBackwards; animation.startProgress = 0.01; animation.endProgress = 0.99; 使用过渡动画,实现在同一个view上,左推,右推等各种动画,节省一个view;
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *flipButton=[[UIBarButtonItem alloc]
initWithTitle:@"翻转"
style:UIBarButtonItemStyleBordered
target:self
action:@selector(flip:)];
self.navigationItem.rightBarButtonItem=flipButton;
fistView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
fistView.tag=100;
fistView.backgroundColor=[UIColor redColor];
[self.view addSubview:fistView];
secondView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
secondView.tag=101;
secondView.backgroundColor=[UIColor yellowColor];
[self.view addSubview:secondView];
}
-(void)flip:(id)sender{
CGContextRef context=UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
//这里时查找视图里的子视图(这种情况查找,可能时因为父视图里面不只两个视图)
NSInteger fist= [[self.view subviews] indexOfObject:[self.view viewWithTag:100]];
NSInteger seconde= [[self.view subviews] indexOfObject:[self.view viewWithTag:101]];
[self.view exchangeSubviewAtIndex:fist withSubviewAtIndex:seconde];
//当父视图里面只有两个视图的时候,可以直接使用下面这段.
//[self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
- UIViw动画举例
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; _mViewAnim=[[UIView alloc]init]; _mViewAnim.frame=CGRectMake(0, 0, 60, 60); _mViewAnim.backgroundColor=[UIColor redColor]; [self.window addSubview:_mViewAnim]; [self.window makeKeyAndVisible]; return YES; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { static BOOL isFirst=YES; if (isFirst==YES) { //设置开始时的透明度,位置,透明度 _mViewAnim.frame=CGRectMake(0, 0, 60, 60); _mViewAnim.alpha=1.0f; _mViewAnim.backgroundColor=[UIColor blueColor]; [UIView beginAnimations:@"anim01" context:nil]; //动画时间 [UIView setAnimationDuration:4.0f]; //延时启动 [UIView setAnimationDelay:0.0f]; //设置动画结束后的代理对象 [UIView setAnimationDelegate:self]; //设置动画结束事件函数 [UIView setAnimationDidStopSelector:@selector(animStop)]; //设置动画的结束位置,透明度 _mViewAnim.frame=CGRectMake(220, 0, 100, 100); _mViewAnim.backgroundColor=[UIColor grayColor]; _mViewAnim.alpha=1.0f; //提交动画 //[UIView commitAnimations]; isFirst=NO; } else { [UIView beginAnimations:@"anim01" context:nil] ; [UIView setAnimationDuration:2.0f]; //设置动画结束后的代理对象 [UIView setAnimationDelegate:self]; //设置动画结束事件函数 [UIView setAnimationDidStopSelector:@selector(animStop)]; //设置动画的结束位置,透明度 _mViewAnim.frame=CGRectMake(220, 0, 100, 100); _mViewAnim.backgroundColor=[UIColor grayColor]; _mViewAnim.alpha=1.0f; } } -(void)animStop { [UIView beginAnimations:@"anim01" context:nil] ; [UIView setAnimationDuration:5.0f]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animStop1)]; _mViewAnim.frame = CGRectMake(220, 380, 100, 100); _mViewAnim.backgroundColor = [UIColor blueColor]; } -(void)animStop1 { [UIView beginAnimations:@"anim01" context:nil] ; [UIView setAnimationDuration:5.0f]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animStop2)]; _mViewAnim.frame = CGRectMake(0, 380, 100, 100); _mViewAnim.backgroundColor = [UIColor blackColor]; } -(void)animStop2 { [UIView beginAnimations:@"anim01" context:nil] ; [UIView setAnimationDuration:5.0f]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animStop3)]; _mViewAnim.frame = CGRectMake(0, 0, 100, 100); _mViewAnim.backgroundColor = [UIColor yellowColor]; } -(void)animStop3 { //NSLog(@"动画结束"); [UIView setAnimationDidStopSelector:@selector(touchesBegan:withEvent:)]; [UIView commitAnimations]; }
UIView动画
//初始化游戏场景 -(void) startGame { NSMutableArray* _arrayNum =[[NSMutableArray alloc] init] ; for (int i = 0; i < 18; i++) { int random = arc4random() % 7 + 1 ; NSNumber* num = [NSNumber numberWithInt:random] ; [_arrayNum addObject:num] ; [_arrayNum addObject:num] ; } for (int i = 0 ; i < 6; i++) { for (int j = 0 ; j < 6; j++) { //创建按钮,宝石按钮 UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom] ; btn.frame=CGRectMake(0,0,0,0); [UIView beginAnimations:@"开始" context:nil]; [UIView setAnimationDuration:1.0f]; [UIView setAnimationDelay:1.0f]; [UIView setAnimationDelegate:self]; btn.frame = CGRectMake(10+50*j, 40+50*i, 50, 50); [UIView commitAnimations]; int r2 = arc4random() % _arrayNum.count ; int random = [[_arrayNum objectAtIndex:r2] intValue] ; [_arrayNum removeObjectAtIndex:r2] ; //1~7的随机数 //int random = arc4random() % 7 + 1 ; //生成图像名字 NSString* strName = [NSString stringWithFormat:@"%d.png",random] ; //读取图片对象 UIImage* image = [UIImage imageNamed:strName]; [btn setImage:image forState:UIControlStateNormal]; btn.tag = random ; [btn addTarget:self action:@selector(pressBtn:) forControlEvents:UIControlEventTouchUpInside]; [self.window addSubview:btn]; } } } -(void) pressBtn:(UIButton*) btn { //是否为按下第一个图片 //static BOOL isFirstPress = YES ; //记录按下的第一个按钮的对象 static UIButton* btnFirst = nil ; //按下第一个宝石 if (btnFirst == nil) { btnFirst = btn ; //取消按钮的交互 btnFirst.enabled = NO ; } //按下第二个宝石 else { //如果是同样的宝石 if (btnFirst.tag == btn.tag) { //隐藏按钮 btnFirst.hidden = YES ; btn.hidden = YES ; //btn.hidden = NO ; } else { //开启交互 btnFirst.enabled = YES ; } //清空第一个宝石 btnFirst = nil ; } }
- x轴缩放:
CABasicAnimation *theAnimation;
theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
theAnimation.duration=8;
theAnimation.removedOnCompletion = YES;
theAnimation.fromValue = [NSNumber numberWithFloat:1];
theAnimation.toValue = [NSNumber numberWithFloat:0.5];
[yourView.layer addAnimation:theAnimation forKey:@"animateTransform"];
y轴缩放:
CABasicAnimation *theAnimation;
theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
theAnimation.duration=8;
theAnimation.removedOnCompletion = YES;
theAnimation.fromValue = [NSNumber numberWithFloat:1];
theAnimation.toValue = [NSNumber numberWithFloat:0.5];
[yourView.layer addAnimation:theAnimation forKey:@"animateTransform"];
x轴,y轴同时按比例缩放:
CABasicAnimation *theAnimation;
theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
theAnimation.duration=8;
theAnimation.removedOnCompletion = YES;
theAnimation.fromValue = [NSNumber numberWithFloat:1];
theAnimation.toValue = [NSNumber numberWithFloat:0.5];
[yourView.layer addAnimation:theAnimation forKey:@"animateTransform"];
以上缩放是以view的中心点为中心缩放的,如果需要自定义缩放点,可以设置卯点:
//中心点
[yourView.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
//左上角
[yourView.layer setAnchorPoint:CGPointMake(0, 0)];
//右下角
[yourView.layer setAnchorPoint:CGPointMake(1, 1)];
- x轴缩放:
/**
@implementation UIView (i7Rotate360)
- (void)rotate360WithDuration:(CGFloat)aDuration repeatCount:(CGFloat)aRepeatCount timingMode:(enum i7Rotate360TimingMode)aMode {
CAKeyframeAnimation *theAnimation = [CAKeyframeAnimation animation];
theAnimation.values = [NSArray arrayWithObjects:
[NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, 0,1,0)],
[NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.14, 0,1,0)],
[NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.14, 0,1,0)],
[NSValue valueWithCATransform3D:CATransform3DMakeRotation(6.28, 0,1,0)],
nil];
theAnimation.cumulative = YES;
theAnimation.duration = aDuration;
theAnimation.repeatCount = aRepeatCount;
theAnimation.removedOnCompletion = YES;
if(aMode == i7Rotate360TimingModeEaseInEaseOut)
{
theAnimation.timingFunctions =
[NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
nil
];
}
[self.layer addAnimation:theAnimation forKey:@"transform"];
}
- (void)rotate360WithDuration:(CGFloat)aDuration timingMode:(enum i7Rotate360TimingMode)aMode {
[self rotate360WithDuration:aDuration repeatCount:1 timingMode:aMode];
}
- (void)rotate360WithDuration:(CGFloat)aDuration {
[self rotate360WithDuration:aDuration repeatCount:1 timingMode:i7Rotate360TimingModeEaseInEaseOut];
}
*/
@implementation HeadPhotoRotationViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.view. backgroundColor = [UIColor grayColor];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 头像
_headImageView = [[UIImageView alloc] init];
_headImageView.backgroundColor = [UIColor clearColor];
_headImageView.frame = CGRectMake(100, 300, 100, 100);
_headImageView.layer.cornerRadius = 50.0;
_headImageView.layer.borderWidth = 1.0;
_headImageView.layer.borderColor = [UIColor whiteColor].CGColor;
_headImageView.layer.masksToBounds = YES;
_headImageView.image = [UIImage imageNamed:@"head1.jpg"];
[self.view addSubview:_headImageView];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(100, 100, 100, 100);
[btn setTitle:@"点击旋转" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[self.view addSubview:btn];
[btn addTarget:self action:@selector(actionRotation:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)actionRotation:(UIButton *)button
{
[self performSelector:@selector(headPhotoAnimation) withObject:nil afterDelay:0.7];
}
- (void)headPhotoAnimation
{
[_headImageView rotate360WithDuration:2.0 repeatCount:1 timingMode:i7Rotate360TimingModeLinear];
_headImageView.animationDuration = 2.0;
_headImageView.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:@"head1.jpg"],
[UIImage imageNamed:@"head2.jpg"],[UIImage imageNamed:@"head2.jpg"],
[UIImage imageNamed:@"head2.jpg"],[UIImage imageNamed:@"head2.jpg"],
[UIImage imageNamed:@"head1.jpg"], nil];
_headImageView.animationRepeatCount = 1;
[_headImageView startAnimating];
}