某种意义 上苹果已经提供了优美简洁的UIView接口,对简单需求没必要处理CALayer,因为苹果已经通过UIView 的高级API 间接地使得动画变得很简单。
但简单就不可避免地带来灵活上的缺陷,UIView 没有暴露CALayer的功能:
- 阴影,圆角,带颜色的边框
- 3D 变换
- 非矩形范围
- 透明遮罩
- 多级非线性动画
基础属性
UIImage *image = [UIImage imageNamed:@"1.jpg"];
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(0, 0, 300, 400);
[self.view.layer addSublayer:layer];
self.myLayer = layer;
//1.contents 属性(id 类型)
//image.CGImage 返回一个CGImageRef 指向CGImage结构的指针
//CGImageRef 不是Cocoa对象,而是一个Core Foundation 类型,需要 __bridge转换
layer.contents = (__bridge id)image.CGImage;
//2. imageView图片有contentMode 属性设置图片填充方式
layer.contentsGravity = ;//不被拉伸
//3. maskToBounds 相当于 clipsToBounds 属性来设置边界
//默认情况下,UIView 和 CALayer 都会绘制走出边界的内容或子视图
//4. contentsRect 允许我们在图层边框里显示寄宿图的一个子域
//它使用单位坐标(0-1),是一个相对值,是相对于寄宿图的尺寸而言
//这个属性可以将加载的一张图片,切成多张图片
layer.contentsRect = CGRectMake(0.4, 0.2, 0.3, 0.3);
//5. UIView 有三个布局属性 frame,bounds,center
//CALayer 有三个布局属性 frame,bounds,position
//frame 是外部坐标,bounds 是内部坐标
//当操纵视图的 frame,实际上是在改变位于视图下方 CALayer 的 frame
//当视图旋转后,其frame 与 bounds 一般会不一致。因为frame 代表了覆盖在
//图层旋转后整个轴对齐的矩形区域。
//6. 锚点
//anchorPoint默认居中(0.5,0.5),可以理解为移动图层的把柄
//可以通过移动锚点来改变 frame,锚点改变后,其旋转中心点也改变
//7. conrnerRadius属性控制图层的曲率,只影响背景颜色而不影响子视图
//maskToBounds 设成 YES,才会有截取
//borderColor 设置边框颜色
//borderWidth 设置边框粗细
//8. shadowColor 阴影颜色
//shadowOffset 阴影方向及距离
//shadowRadius 阴影模糊度
//shadowPath 阴影路径
//注意:开启了masksToBounds 属性,越界全被截剪,阴影则无法显示
//9. mask 属性本身也是一个CALayer类型
//opacity 与 alpha 相似,都会影响子图层。
//10. 当有多个子视图时,由于透明度叠加造成效果很不理想。
//shouldRasterize 属性会将多个图层整合成整体图片然后设置透明度
//self.myLayer.shouldRasterize = YES;
//11. 变换
//UIView transform 属性,CGAffineTransform 类型(二维坐标系)
//CALayer transform 属性,CATransform3D 类型 (三维坐标第)
// affineTransform 属性,CGAffineTransform类型
//layer.affineTransform = CGAffineTransformMakeRotation(M_PI/4);
//混合变换
/*
CGAffineTransform transform = CGAffineTransformIdentity;//初始空值
transform = CGAffineTransformScale(transform, 0.5, 0.5);
transform = CGAffineTransformRotate(transform, M_PI/4);
transform = CGAffineTransformTranslate(transform, 10, 30);
layer.affineTransform = transform;
*/
//或者
//CGAffineTransformConcat(transform, transform);
//旋转
//基于最初的位置旋转
//self.myLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
//基于给定的transform 旋转
//self.myLayer.transform = CATransform3DRotate(self.myLayer.transform, M_PI, 0, 1, 0);
//**********透视效果,默认通过 m34 来改变*************
//CATransform3D transform = CATransform3DIdentity;
//transform.m34 = -1.0/500; //(500-1000是一个比较和适的值)
//transform = CATransform3DRotate(transform, M_PI_4, 1, 0, 0);
//layer.transform = transform;
//12. 背面,当视图旋转后背面不会被绘制
//self.myLayer.doubleSided = NO;
CATransition (过渡动画)
- CATransition动画可以实现别样的轮播图动效
- (void)transitionAnimation{
CATransition *transition = [CATransition animation];
transition.fillMode = kCAFillModeForwards;
transition.removedOnCompletion = YES;
transition.startProgress = 0.0;
transition.endProgress = 1.0;
transition.duration = 1.0;
transition.type = kCATransitionMoveIn;
/*
私有接口(慎用)
cube 立体翻转
oglFlip 翻转
suckEffect 收缩效果
rippleEffect 水滴波纹
pageCurl 翻页
pageUnCurl
cameralIrisHollowOpen 摄像头打开效果
cameraIrisHollowClose 关闭效果
*/
/*
公有接口
kCATransitionFade 淡出效果
kCATransitionMoveIn 新视图移到旧视图上
kCATransitionPush 新视图推出旧视图
kCATransitionReveal 移开旧视图显示新视图
*/
transition.subtype = kCATransitionFromLeft;
/*
kCATransitionFromRight
kCATransitionFromLeft
kCATransitionFromTop
kCATransitionFromBottom
*/
[self.imageView.layer addAnimation:transition forKey:@"transition"];
[self setNewImage];
}
只要用手势或计时器回调下面方法即可实现轮播效果
- (void)setNewImage{
static int i = 5;
i++;
int imageIndex = i%5;
NSString *imageName = [NSString stringWithFormat:@"%d.jpg",imageIndex];
[self.imageView setImage:[UIImage imageNamed:imageName]];
}
或者
[UIView transitionWithView:_imageView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
// [self.imageView setFrame:CGRectMake(0, 0, 300, 300)];
[self setNewImage];
} completion:nil];
- CATransition动画实现简单的转场效果
// 在window上执行CATransition, 即可在ViewController转场时执行动画。
[self.view.window.layer addAnimation:animation forKey:@"kTransitionAnimation"];
PresentedViewController *presentedVC = [[PresentedViewController alloc] init];
[self presentViewController:presentedVC animated:NO completion:nil];
- tabBarViewController 可以添加过渡效果
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *viewController1 = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc]initWithNibName:@"SecondViewController" bundle:nil];
viewController2.title = @"第一";
viewController1.title = @"第二";
self.tabBarController = [[UITabBarController alloc]init];
self.tabBarController.viewControllers = @[viewController1,viewController2];
self.tabBarController.delegate = self;
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
CATransition *transition = [CATransition animation];
transition.type = kCATransitionFade;
transition.duration= 3; //3秒时间过渡效果会明显一些
[self.tabBarController.view.layer addAnimation:transition forKey:@"transition"];
}
CAKeyframeAnimation
- (void)keyFrameAnimation{
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.view.center
radius:100
startAngle:0
endAngle:2 * M_PI
clockwise:YES];//顺时针方向
keyframeAnimation.path = path.CGPath;//UIKit框架转CG框架
keyframeAnimation.duration = 3;
keyframeAnimation.repeatCount = 1;
keyframeAnimation.fillMode = kCAFillModeForwards;
keyframeAnimation.removedOnCompletion = NO;
keyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
//这个属性很有意思。
keyframeAnimation.rotationMode = KCAAnimationRotateAuto;
//*******设置value后会覆盖path********//
//KeyframeAnimation.values = @[ ];
[self.layer addAnimation:keyframeAnimation forKey:@"keyframeAnimation"];
}
- (void)addShakeAnimationForView:(UIView *)view withDuration:(NSTimeInterval)duration {
CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
CGFloat currentTx = view.transform.tx;
animation.delegate = self;
animation.duration = duration;
animation.values = @[ @(currentTx), @(currentTx + 10), @(currentTx-8), @(currentTx + 8), @(currentTx -5), @(currentTx + 5), @(currentTx) ];
animation.keyTimes = @[ @(0), @(0.225), @(0.425), @(0.6), @(0.75), @(0.875), @(1) ];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.layer addAnimation:animation forKey:@"keyframeAnimation"];
}
CABasicAnimation
/**
* CABsicAnimation 的实例对象只是一个数据模型,
* addAnimation:forKey只是将对象的copy,所以也可以添加到另外一个layer上
*
*/
/**
* 为什么动画会返回原状态
* 添加动画时,真正移动的并不是视图本身,而是presentation Layer的一个缓存
* 动画开始,presentation Layer开始移动,原始layer隐藏
* 动画结束,presentation layer开始移除,原始layer显示
*/
- (void)basicAnimation{
//旋转动画
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
rotateAnimation.duration = 3.0;
rotateAnimation.repeatCount = 100;
rotateAnimation.autoreverses = YES;
rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
rotateAnimation.toValue = [NSNumber numberWithFloat:6*M_PI];
[self.layer addAnimation:rotateAnimation forKey:@"rotate"];
//放大 缩小
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.duration = 3.0;
scaleAnimation.repeatCount = 1;
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:3];
//动画结束后保持移动后的位置
scaleAnimation.removedOnCompletion = NO;
scaleAnimation.fillMode = kCAFillModeForwards;
//设置动画速率
scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
/**
* kCAMediaTimingFunctionLinear
* kCAMediaTimingFunctionEaseIn 开始慢,后来快
* kCAMediaTimingFunctionEaseOut
*/
[self.layer addAnimation:scaleAnimation forKey:@"scale"];
//设置代理可以监测动画开始和结束时的动作
scaleAnimation.delegate = self;
//平移动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.duration = 3.0;
animation.autoreverses = YES;
animation.repeatCount = 100;
animation.fromValue = [NSValue valueWithCGPoint:_layer.position];
CGPoint toPoint = _layer.position;
toPoint.x = toPoint.x+180;
animation.toValue = [NSValue valueWithCGPoint:toPoint];
[self.layer addAnimation:animation forKey:@"move"];
}
UIView动画
- 动画使用
3D变换可将图层顺序更改
动画中更改使用transform可以快速方便地改变frame
[UIView animateWithDuration:0.5 animations:^{
self.testView.layer.transform = CATransform3DMakeTranslation(10, 10, 1);
} completion:nil];
[UIView animateWithDuration:0.5 animations:^{
self.testView.transform = CGAffineTransformMakeTranslation(10, 10);
} completion:nil];
或
-(void)normalAnimation{
[UIView animateWithDuration:2
delay:1
options:UIViewAnimationOptionRepeat
animations:^{
[UIView setAnimationRepeatCount:3];
[UIView setAnimationRepeatAutoreverses:YES];
self.redView.center = self.view.center;
}
completion:^(BOOL finished){
NSLog(@"finished--%d",finished); }
];
}
或
UIViewAnimationOptions op = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState;
[UIView animateWithDuration:0.1
delay:0
options:op
animations:^{
//view缩小
[_view.layer setValue:@(0.5) forKeyPath:@"transform.scale"];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 delay:0 options:op animations:^{
// view放大
[_view.layer setValue:@(1.08) forKeyPath:@"transform.scale"];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 delay:0 options:op animations:^{
//view恢得原样
[_view.layer setValue:@(1) forKeyPath:@"transform.scale"];
} completion:NULL];
}];
}];
- spring动画
-(void)springAnimation{
[UIView animateWithDuration:1
delay:0
usingSpringWithDamping:100//类似弹簧振动效果,越小越明显
initialSpringVelocity:10 //初始速度
options:UIViewAnimationOptionCurveLinear
animations:^{
[UIView setAnimationRepeatCount:5];
self.redView.frame = CGRectMake(50, 200, 100, 100);
}
completion:^(BOOL finished) {
}];
}
- 关键帧动画
-(void)keyFrameAnimationView{
[UIView animateKeyframesWithDuration:6
delay:0.0
options:UIViewKeyframeAnimationOptionLayoutSubviews
animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.3 animations:^{
self.redView.center = self.view.center;
}];
[UIView addKeyframeWithRelativeStartTime:0.3 relativeDuration:0.3 animations:^{
self.redView.backgroundColor = [UIColor orangeColor];
}];
[UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.4 animations:^{
CGRect rect= self.redView.frame;
rect.size.width +=rect.size.width;
rect.size.height +=rect.size.height;
self.redView.frame =rect;
}];
//relativeStartTime
//relativeDuration 都是相对时间,占总时间的占比
} completion:^(BOOL finished) {
NSLog(@"动画结束");
}];
}
UIView动画停止
- (void)startAnimation {
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveLinear |
UIViewAnimationOptionAllowUserInteraction
animations:^(void) {
//动画
} completion:^(BOOL finished) {
if(!self.canceled) {
__weak id weakSelf = self;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[weakSelf startAnimation];
}];
}
}];
}