原文参考:
coreAnimation官方资料翻译:
CATransfrom3D
IOS动画中的枚举UIViewAnimationOptions
概览
在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画、关键帧动画、动画组、转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等。在今天的文章里您可以看到动画操作在iOS中是如何简单和高效,很多原来想做但是苦于没有思路的动画在iOS中将变得越发简单:
- CALayer
- CALayer简介
- CALayer常用属性
- CALayer绘图
- Core Animation
- 基础动画
- 关键帧动画
- 动画组
- 转场动画
- 逐帧动画
- UIView动画封装
- 基础动画
- 关键帧动画
- 转场动画

CALayer
在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮,一个文本标签,一个文本输入框,一个图标等等,这些都是UIView.
UIView之所以能显示在屏幕上,完全是因为它内部的一个图层.
UIView的显示原理
在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个图层.
@property(nonatomic,readonly,retain) CALayer *layer;
当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有的内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView的显示.
换句话说,UIView本身不具备显示的功能,是它内部的层才有显示功能.
CALayer的基本使用
通过操作CALayer对象,可以很方便的调整UIView的一些外观属性,比如阴影, 圆角大小, 边框宽度和颜色等.还可以给图层添加动画来实现一些比较炫酷的效果.
CALayer的属性
// 宽度和高度
@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 .
@property CGPoint position;
用来设置CALayer在父层中的位置,以父层的左上角为原点(0,0).
@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)关闭默认的隐式动画效果;
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];
CATransion应用举例
- (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];
}CATransition *animation = [CATransition animation];
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;pageCurl 向上翻一页使用过渡动画,实现在同一个view上,左推,右推等各种动画,节省一个view;IOS利用UIView的动画实现视图翻转效果
- (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的中心点为中心缩放的,如果需要自定义缩放点,可以设置卯点:
1. //中心点
[yourView.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
//左上角
[yourView.layer setAnchorPoint:CGPointMake(0, 0)];
//右下角
[yourView.layer setAnchorPoint:CGPointMake(1, 1)];绕Y轴旋转360度的做法,方法:给关键帧设置values,然后更新图片
/**
@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];
}
















