CAEmitterLayer&CAEmitterCell 属性详讲
CAEmitterLayer
可实现⾼性能的粒子引擎,被⽤来创建实现粒子动画;⽐如烟雾、⽕、⾬等效果。
CAEmitterLayer常用属性
@property @property(nullable, copy copy) NSArray *emitterCells; // 用来装粒子的数组
@property @property float float birthRate; // 粒子产生系数,默认1.0
@property @property float float lifetime; // 粒子的生命周期系数,默认1.0
@property @property CGPoint emitterPosition; // 决定了粒子发射形状的中心点
@property @property CGFloat emitterZPosition;
@property @property CGSize emitterSize; // 发射源的尺寸大小
@property @property CGFloat emitterDepth;
@property @property(copy copy) NSString *emitterShape; // 发射源的形状
@property @property(copy copy) NSString *emitterMode; // 发射模式
@property @property(copy copy) NSString *renderMode; // 渲染模式
@property @property BOOL preservesDepth;
@property @property float float velocity; // 粒子速度系数,默认1.0
@property @property float float scale; // 粒子的缩放比例系数,默认1.0
@property @property float float spin; // 粒子的自旋转速度系数,默认1.0
@property @property unsigned unsigned int int seed; // 随机数发生器
CAEmitterLayer
发射的粒子并不是杂乱无章的,我们可以设置它发射粒子时的位置、几何图形等。通过以下属性去配置
-
emitterPosition:
决定发射源的中心点
1.如设置layer.emitterPosition = CGPointMake(self.view.bounds.size.width * 0.5, -10);
表示x轴方向上就是view的中心点
2.再设置layer.emitterSize = CGSizeMake(40, 0);
的话,就表示self.view.bounds.size.width * 0.5
左右两边各20
3.API
还提供了一个emitterZPosition
,主要是用在三维坐标中表示深度位置 -
emitterSize:
决定发射源的大小 -
emitterShape:
表示粒子以什么形状发射出来
1.kCAEmitterLayerPoint
点形状,发射源的形状就是一个点,位置就是emitterPosition
设置的位置
2.kCAEmitterLayerLine
线形状,发射源的形状是一条线,位置在rect
横向位于垂直方向中间那条
3.kCAEmitterLayerRectangle
矩形状,发射源的形状是一个矩形,就是上面生成的那个矩形rect
4.kCAEmitterLayerCuboid
立体矩形形状(3D),发射源是一个立体矩形,需要设置z
方向的数据才能生效,否则就同矩形状
5.kCAEmitterLayerCircle
圆形形状,发射源是一个圆形,形状为矩形包裹的那个圆,二维的
6.kCAEmitterLayerSphere
立体圆形(3D),三维的圆形,同样需要设置z
方向的数据,不设置同二维一样
比如设置的红包效果,就是用的kCAEmitterLayerLine
,并结合了emitterSize
来实现从顶部掉下来的效果,而emitterSize
的height
其实是被忽略的。
redpacketLayer.emitterPosition = CGPointMake(100, 100);
redpacketLayer.emitterSize = CGSizeMake(20, 0);
redpacketLayer.emitterShape = kCAEmitterLayerLine;
-
emitterMode:
发射模式,决定了在特定形状上发射的具体形式是什么。其实就是决定发射的区域在发射形状的哪一部分。
1.kCAEmitterLayerPoints
点模式,发射器是以点的形式发射粒子。如果发射形状是圆形,该点就表示圆心。
2.kCAEmitterLayerOutline
轮廓模式,从形状的边界上发射粒子。
3.kCAEmitterLayerSurface
表面模式,从形状的表面上发射粒子。
4.kCAEmitterLayerVolume
是相对于3D形状的球体内
或立方体内
发射。
CAEmitterCell常用属性
CAEmitterLayer
就是粒子的工厂,要想实现效果就需要用到CAEmitterCell
@property(nullable, copy) NSString *name; // 粒子名字,默认为nil @property(getter=isEnabled) BOOL enabled;
@property float birthRate; // 粒子的产生率,默认0
@property float lifetime; // 粒子的生命周期,以秒为单位。默认0
@property float lifetimeRange; // 粒子的生命周期的范围,以秒为单位。默认为0
@property CGFloat emissionLatitude;// 指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴之间的夹角,默认0:
@property CGFloat emissionLongitude; // 指定经度,经度角代表了在x-y轴平面坐标系中与x轴之间的夹角,默认0:
@property CGFloat emissionRange; //发射角度范围,默认0,以锥形分布开的发射角度。角度用弧度制。粒子均匀分布在这个锥形范围内;
@property CGFloat velocity; // 速度和速度范围,两者默认0
@property CGFloat velocityRange;
@property CGFloat xAcceleration; // x,y,z方向上的加速度分量,三者默认都是0
@property CGFloat yAcceleration;
@property CGFloat zAcceleration;
@property CGFloat scale; // 缩放比例, 默认是1
@property CGFloat scaleRange; // 缩放比例范围,默认是0
@property CGFloat scaleSpeed; // 在生命周期内的缩放速度,默认是0 @property CGFloat spin; // 粒子的平均旋转速度,默认是0
@property CGFloat spinRange; // 自旋转角度范围,弧度制,默认是0 @property(nullable) CGColorRef color; // 粒子的颜色,默认白色
@property float redRange; // 粒子颜色red,green,blue,alpha能改变的范围, 默认0
@property float greenRange;
@property float blueRange;
@property float alphaRange;
@property float redSpeed; // 粒子颜色red,green,blue,alpha在生命周期内的改变速度,默认都是0
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;
@property(nullable, strong) id contents; // 粒子的内容,为CGImageRef 的对象
@property CGRect contentsRect;
@property CGFloat contentsScale;
@property(copy) NSString *minificationFilter;
@property(copy) NSString *magnificationFilter;
@property float minificationFilterBias;
@property(nullable, copy) NSArray *emitterCells; //粒子里面的粒子
@property(nullable, copy) NSDictionary *style;
CAEmitterCell
中决定生命状态的属性
-
lifetime、lifetimeRange:
粒子在系统上的生命周期,即存活时间,单位是秒。配合lifetimeRage
来让粒子生命周期均匀变化,以便可以让粒子的出现和消失显的更加离散。 -
birthRate
每秒钟产生的粒子数量,是浮点数。
CAEmitterCell
中决定内容的属性
-
contents:
为CGImageRef
的对象。 -
name:
粒子的名字
CAEmitterCell
中决定颜色状态的属性
-
color:
是粒子的颜色属性,作用是给粒子上色 -
redRange、greenRange、blueRange、alphaRange:
对应的color的RGBA
的取值范围,范围值为0~1
-
redSpeed、greenSpeed、blueSpeed、alphaSpeed:
对应的粒子的RGBA
变化速度,取值范围为0~1
,表示每秒钟的RGBA
的变化率。
CAEmitterCell
中决定飞行轨迹的属性:emissionLongitude、emissionLatitude、 emissionRange
CAEmitterCell
的子粒子属性:emitterCells
粒子效果案例实现
下面我们使用CAEmitterLayer
、CAEmitterCell
实现粒子效果
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) CAEmitterLayer * colorBallLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self setupEmitter];
}
- (void)setupEmitter{
UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 50)];
[self.view addSubview:label];
label.textColor = [UIColor whiteColor];
label.text = @"轻点或拖动来改变发射源位置";
label.textAlignment = NSTextAlignmentCenter;
// 粒子:大批量产生颗粒效果,主要有两个类:
// 发射类 - CAEmitterLayer是发射源,支持多种粒子效果
// 发射粒子 - CAEmitterCell表示每一种对应的粒子效果
/*
CAEmitterLayer
emitterPosition:粒子发射形状的中心点
emitterShape:发射源的形状
kCAEmitterLayerPoint - 点形状
kCAEmitterLayerLine - 线段形状
kCAEmitterLayerRectangle - 矩形状
kCAEmitterLayerCuboid - 立体矩阵块(3D)
kCAEmitterLayerCircle - 圆形
kCAEmitterLayerSphere - 立体圆形(3D)
emitterMode: 发射模式
kCAEmitterLayerPoints - 点模式
kCAEmitterLayerOutline - 轮廓模式
kCAEmitterLayerSurface - 表面模式
kCAEmitterLayerVolume - 3D发射模式
*/
// 1. 设置CAEmitterLayer,创建发射源
CAEmitterLayer * colorBallLayer = [CAEmitterLayer layer];
[self.view.layer addSublayer:colorBallLayer];
self.colorBallLayer = colorBallLayer;
//发射源的尺寸大小
colorBallLayer.emitterSize = self.view.frame.size;
//发射源的形状
colorBallLayer.emitterShape = kCAEmitterLayerPoint;
//发射模式
colorBallLayer.emitterMode = kCAEmitterLayerPoints;
//粒子发射形状的中心点
colorBallLayer.emitterPosition = CGPointMake(self.view.layer.bounds.size.width, 0.f);
// 2. 配置CAEmitterCell
CAEmitterCell * colorBallCell = [CAEmitterCell emitterCell];
//粒子名称
colorBallCell.name = @"colorBallCell";
//粒子产生率,默认为0
colorBallCell.birthRate = 20.f;
//粒子生命周期
colorBallCell.lifetime = 10.f;
//粒子速度,默认为0
colorBallCell.velocity = 40.f;
//粒子速度平均量
colorBallCell.velocityRange = 100.f;
//x,y,z方向上的加速度分量,三者默认都是0
colorBallCell.yAcceleration = 15.f;
//指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴之间的夹角,默认0:
colorBallCell.emissionLongitude = M_PI; // 向左
//发射角度范围,默认0,以锥形分布开的发射角度。角度用弧度制。粒子均匀分布在这个锥形范围内;
colorBallCell.emissionRange = M_PI_4; // 围绕X轴向左90度
// 缩放比例, 默认是1
colorBallCell.scale = 0.2;
// 缩放比例范围,默认是0
colorBallCell.scaleRange = 0.1;
// 在生命周期内的缩放速度,默认是0
colorBallCell.scaleSpeed = 0.02;
// 粒子的内容,为CGImageRef的对象
colorBallCell.contents = (id)[[UIImage imageNamed:@"circle_white"] CGImage];
//颜色
colorBallCell.color = [[UIColor colorWithRed:0.5 green:0.f blue:0.5 alpha:1.f] CGColor];
// 粒子颜色red,green,blue,alpha能改变的范围,默认0
colorBallCell.redRange = 1.f;
colorBallCell.greenRange = 1.f;
colorBallCell.alphaRange = 0.8;
// 粒子颜色red,green,blue,alpha在生命周期内的改变速度,默认都是0
colorBallCell.blueSpeed = 1.f;
// 透明度从1.0慢慢变成0.8,是减小的,所以要用负值
colorBallCell.alphaSpeed = -0.1f;
// 添加
colorBallLayer.emitterCells = @[colorBallCell];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint point = [self locationFromTouchEvent:event];
[self setBallInPsition:point];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint point = [self locationFromTouchEvent:event];
[self setBallInPsition:point];
}
/**
* 获取手指所在点
*/
- (CGPoint)locationFromTouchEvent:(UIEvent *)event{
UITouch * touch = [[event allTouches] anyObject];
return [touch locationInView:self.view];
}
/**
* 移动发射源到某个点上
*/
- (void)setBallInPsition:(CGPoint)position{
//创建基础动画
CABasicAnimation * anim = [CABasicAnimation animationWithKeyPath:@"emitterCells.colorBallCell.scale"];
//fromValue
anim.fromValue = @0.2f;
//toValue
anim.toValue = @0.5f;
//duration
anim.duration = 1.f;
//线性起搏,使动画在其持续时间内均匀地发生
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
// 用事务包装隐式动画,这种动画是通过runloop执行的
[CATransaction begin];
//设置是否禁止由于该事务组内的属性更改而触发的操作。
[CATransaction setDisableActions:YES];
//为colorBallLayer 添加动画
[self.colorBallLayer addAnimation:anim forKey:nil];
//为colorBallLayer 指定位置添加动画效果
[self.colorBallLayer setValue:[NSValue valueWithCGPoint:position] forKeyPath:@"emitterPosition"];
//提交动画
[CATransaction commit];
}
@end
注意:重新切换粒子发射源的位置时,之前的粒子要等到它的生命周期结束才会消失
。
粒子效果实现下雨场景
将下雨的背景图
跟雨点图
素材拖入工程中,添加下雨场景代码如下
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) CAEmitterLayer * rainLayer;
@property (nonatomic, weak) UIImageView * imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self setupEmitter];
}
- (void)setupUI{
// 背景图片
UIImageView * imageView = [[UIImageView alloc]initWithFrame:self.view.frame];
[self.view addSubview:imageView];
self.imageView = imageView;
imageView.image = [UIImage imageNamed:@"rain"];
// 下雨按钮
UIButton * startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:startBtn];
startBtn.frame = CGRectMake(20, self.view.bounds.size.height - 60, 80, 40);
startBtn.backgroundColor = [UIColor whiteColor];
[startBtn setTitle:@"雨停了" forState:UIControlStateNormal];
[startBtn setTitle:@"下雨" forState:UIControlStateSelected];
[startBtn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[startBtn setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
[startBtn addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
// 雨量按钮
UIButton * rainBIgBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:rainBIgBtn];
rainBIgBtn.tag = 100;
rainBIgBtn.frame = CGRectMake(140, self.view.bounds.size.height - 60, 80, 40);
rainBIgBtn.backgroundColor = [UIColor whiteColor];
[rainBIgBtn setTitle:@"下大点" forState:UIControlStateNormal];
[rainBIgBtn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[rainBIgBtn addTarget:self action:@selector(rainButtonClick:) forControlEvents:UIControlEventTouchUpInside];
UIButton * rainSmallBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:rainSmallBtn];
rainSmallBtn.tag = 200;
rainSmallBtn.frame = CGRectMake(240, self.view.bounds.size.height - 60, 80, 40);
rainSmallBtn.backgroundColor = [UIColor whiteColor];
[rainSmallBtn setTitle:@"太大了" forState:UIControlStateNormal];
[rainSmallBtn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[rainSmallBtn addTarget:self action:@selector(rainButtonClick:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonClick:(UIButton *)sender{
if (!sender.selected) {
sender.selected = !sender.selected;
NSLog(@"雨停了");
// 停止下雨
// 1. 移除layer,这种方法不美观
// 2. 修改birthRate的值,推荐使用这种方案
// 停止下雨
[self.rainLayer setValue:@0.f forKeyPath:@"birthRate"];
}else{
sender.selected = !sender.selected;
NSLog(@"开始下雨了");
// 开始下雨
[self.rainLayer setValue:@1.f forKeyPath:@"birthRate"];
}
}
- (void)rainButtonClick:(UIButton *)sender{
NSInteger rate = 1;
CGFloat scale = 0.05;
if (sender.tag == 100) {
NSLog(@"下大了");
if (self.rainLayer.birthRate < 30) {
[self.rainLayer setValue:@(self.rainLayer.birthRate + rate) forKeyPath:@"birthRate"];
[self.rainLayer setValue:@(self.rainLayer.scale + scale) forKeyPath:@"scale"];
}
}else if (sender.tag == 200){
NSLog(@"变小了");
if (self.rainLayer.birthRate > 1) {
[self.rainLayer setValue:@(self.rainLayer.birthRate - rate) forKeyPath:@"birthRate"];
[self.rainLayer setValue:@(self.rainLayer.scale - scale) forKeyPath:@"scale"];
}
}
}
- (void)setupEmitter{
// 1. 设置CAEmitterLayer
CAEmitterLayer * rainLayer = [CAEmitterLayer layer];
// 2.在背景图上添加粒子图层
[self.imageView.layer addSublayer:rainLayer];
self.rainLayer = rainLayer;
//3.发射形状--线性
rainLayer.emitterShape = kCAEmitterLayerLine;
//发射模式
rainLayer.emitterMode = kCAEmitterLayerSurface;
//发射源大小
rainLayer.emitterSize = self.view.frame.size;
//发射源位置 y最好不要设置为0 最好<0
rainLayer.emitterPosition = CGPointMake(self.view.bounds.size.width * 0.5, -10);
// 2. 配置cell
CAEmitterCell * snowCell = [CAEmitterCell emitterCell];
//粒子内容
snowCell.contents = (id)[[UIImage imageNamed:@"rain_white"] CGImage];
//每秒产生的粒子数量的系数
snowCell.birthRate = 25.f;
//粒子的生命周期
snowCell.lifetime = 20.f;
//speed粒子速度.图层的速率。用于将父时间缩放为本地时间,例如,如果速率是2,则本地时间的进度是父时间的两倍。默认值为1。
snowCell.speed = 10.f;
//粒子速度系数, 默认1.0
snowCell.velocity = 10.f;
//每个发射物体的初始平均范围,默认等于0
snowCell.velocityRange = 10.f;
//粒子在y方向的加速的
snowCell.yAcceleration = 1000.f;
//粒子缩放比例: scale
snowCell.scale = 0.1;
//粒子缩放比例范围:scaleRange
snowCell.scaleRange = 0.f;
// 4 .添加到图层上
rainLayer.emitterCells = @[snowCell];
}
@end
粒子效果实现QQ点赞按钮
动画分析
- 点赞先把按钮放大 -> 缩小
CAKeyFrameAnimation
- 放大之后,一个圈的粒子效果:
CAEmitterLayer
实现思路
- 自定义按钮(重写高亮方法)选中/默认状态
- 配置
CAEmitterLayer
与CAEmitterCell
自定义点赞按钮CCLikeButton
#import
@interface CCLikeButton : UIButton
@end
#import "CCLikeButton.h"
@interface CCLikeButton()
@property(nonatomic,strong)CAEmitterLayer *explosionLayer;
@end
@implementation CCLikeButton
- (void)awakeFromNib{
[super awakeFromNib];
//设置粒子效果
[self setupExplosion];
}
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self setupExplosion];
}
return self;
}
//设置粒子
- (void)setupExplosion{
// 1. 粒子
CAEmitterCell * explosionCell = [CAEmitterCell emitterCell];
explosionCell.name = @"explosionCell";
//透明值变化速度
explosionCell.alphaSpeed = -1.f;
//alphaRange透明值范围
explosionCell.alphaRange = 0.10;
//生命周期
explosionCell.lifetime = 1;
//生命周期range
explosionCell.lifetimeRange = 0.1;
//粒子速度
explosionCell.velocity = 40.f;
//粒子速度范围
explosionCell.velocityRange = 10.f;
//缩放比例
explosionCell.scale = 0.08;
//缩放比例range
explosionCell.scaleRange = 0.02;
//粒子图片
explosionCell.contents = (id)[[UIImage imageNamed:@"spark_red"] CGImage];
// 2.发射源
CAEmitterLayer * explosionLayer = [CAEmitterLayer layer];
[self.layer addSublayer:explosionLayer];
self.explosionLayer = explosionLayer;
//发射院尺寸大小
self.explosionLayer.emitterSize = CGSizeMake(self.bounds.size.width + 40, self.bounds.size.height + 40);
//emitterShape表示粒子从什么形状发射出来,圆形形状
explosionLayer.emitterShape = kCAEmitterLayerCircle;
//emitterMode发射模型,轮廓模式,从形状的边界上发射粒子
explosionLayer.emitterMode = kCAEmitterLayerOutline;
//renderMode:渲染模式
explosionLayer.renderMode = kCAEmitterLayerOldestFirst;
//粒子cell 数组
explosionLayer.emitterCells = @[explosionCell];
}
-(void)layoutSubviews{
// 发射源位置
self.explosionLayer.position = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5);
[super layoutSubviews];
}
/**
* 选中状态 实现缩放
*/
- (void)setSelected:(BOOL)selected{
[super setSelected:selected];
// 通过关键帧动画实现缩放
CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];
// 设置动画路径
animation.keyPath = @"transform.scale";
if (selected) {
// 从没有点击到点击状态 会有爆炸的动画效果,先放大1.5倍 再放大2倍 再缩小到0.8倍 最后还原
animation.values = @[@1.5,@2.0, @0.8, @1.0];
animation.duration = 0.5;
//计算关键帧方式:
animation.calculationMode = kCAAnimationCubic;
//为图层添加动画
[self.layer addAnimation:animation forKey:nil];
// 让放大动画先执行完毕 再执行爆炸动画
[self performSelector:@selector(startAnimation) withObject:nil afterDelay:0.25];
}else{
// 从点击状态normal状态 无动画效果 如果点赞之后马上取消 那么也立马停止动画
[self stopAnimation];
}
}
// 没有高亮状态
- (void)setHighlighted:(BOOL)highlighted{
[super setHighlighted:highlighted];
}
/**
* 开始动画
*/
- (void)startAnimation{
// 用KVC设置颗粒个数
[self.explosionLayer setValue:@1000 forKeyPath:@"emitterCells.explosionCell.birthRate"];
// 开始动画
self.explosionLayer.beginTime = CACurrentMediaTime();
// 延迟停止动画
[self performSelector:@selector(stopAnimation) withObject:nil afterDelay:0.15];
}
/**
* 动画结束
*/
- (void)stopAnimation{
// 用KVC设置颗粒个数
[self.explosionLayer setValue:@0 forKeyPath:@"emitterCells.explosionCell.birthRate"];
//移除动画
[self.explosionLayer removeAllAnimations];
}
@end
点赞按钮我们已经封装好了,下面我们来使用一下看看效果
#import "ViewController.h"
#import "CCLikeButton.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
//添加点赞按钮
CCLikeButton * btn = [CCLikeButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(200, 150, 30, 130);
[self.view addSubview:btn];
[btn setImage:[UIImage imageNamed:@"dislike"] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"like_orange"] forState:UIControlStateSelected];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)btnClick:(UIButton *)button{
if (!button.selected) { // 点赞
button.selected = !button.selected;
NSLog(@"点赞");
}else{ // 取消点赞
button.selected = !button.selected;
NSLog(@"取消赞");
}
}
@end
多个图层创建3D叠加
下面实现多个图层
叠加的3D
旋转效果,代码如下
#import "ViewController.h"
#define DEGREES_TO_RADIANS(d) (d * M_PI / 180)
@interface ViewController ()
@property (nonatomic, strong) CALayer *rootLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.rootLayer = [CALayer layer];
// 应用透视转换
CATransform3D transform = CATransform3DMakePerspective(1000);
self.rootLayer.sublayerTransform = transform;
self.rootLayer.frame = self.view.bounds;
[self.view.layer addSublayer:self.rootLayer];
//颜色数组
NSArray *colors = @[[UIColor colorWithRed:0.263 green:0.769 blue:0.319 alpha:1.000], [UIColor colorWithRed:0.990 green:0.759 blue:0.145 alpha:1.000], [UIColor colorWithRed:0.084 green:0.398 blue:0.979 alpha:1.000]];
//添加3个图层
[self addLayersWithColors:colors];
[self performSelector:@selector(rotateLayers) withObject:nil afterDelay:1.0];
}
- (void)addLayersWithColors:(NSArray *)colors {
//遍历颜色数组,创建图层
for (UIColor *color in colors) {
//创建图层
CALayer *layer = [CALayer layer];
//颜色
layer.backgroundColor = color.CGColor;
//大小
layer.bounds = CGRectMake(0, 0, 200, 200);
//位置
layer.position = CGPointMake(160, 190);
//透明度
layer.opacity = 0.80;
//圆角
layer.cornerRadius = 10;
//边框颜色
layer.borderColor = [UIColor whiteColor].CGColor;
//边框宽度
layer.borderWidth = 1.0;
//阴影offset ,默认(0,3)
layer.shadowOffset = CGSizeMake(0, 2);
//用于创建阴影的模糊半径。默认值为3。可动画的
layer.shadowOpacity = 0.35;
//阴影颜色
layer.shadowColor = [UIColor darkGrayColor].CGColor;
//是否光栅化
layer.shouldRasterize = YES;
//添加图层
[self.rootLayer addSublayer:layer];
}
}
- (void)rotateLayers {
//创建基本动画以围绕Y轴和Z轴旋转
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
transformAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
transformAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(DEGREES_TO_RADIANS(85), 0, 1, 1)];
transformAnimation.duration = 1.5;
//自动翻转
transformAnimation.autoreverses = YES;
//重复次数
transformAnimation.repeatCount = HUGE_VALF;
//定义动画步调的计时函数
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
int tx = 0;
// 循环浏览子图层并附加动画
for (CALayer *layer in [self.rootLayer sublayers]) {
//为图层添加动画
[layer addAnimation:transformAnimation forKey:nil];
// 创建要沿X轴平移的动画
CABasicAnimation *translateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
translateAnimation.fromValue = [NSValue valueWithCATransform3D:layer.transform];
translateAnimation.toValue = [NSNumber numberWithFloat:tx];
translateAnimation.duration = 1.5;
translateAnimation.autoreverses = YES;
translateAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
translateAnimation.repeatCount = HUGE_VALF;
[layer addAnimation:translateAnimation forKey:nil];
tx += 35;
}
}
//透视投影修改m34值
static CATransform3D CATransform3DMakePerspective(CGFloat z) {
CATransform3D t = CATransform3DIdentity;
t.m34 = - 1.0 / z;
return t;
}
@end
AVPlayerLayer播放视频
AVPlayerLayer
可实现播放视频图层,是AVFoundation
提供的图层,但与CoreAnimation
紧密链接,虽然不是核心动画中的图层,但AVPlayerLayer的父类是CALayer
,就实现核心动画的一些效果。
下面使用AVPlayerLayer
来实现视频的播放
#import
@class AVPlayer;
@interface ViewController : UIViewController
@property (nonatomic, strong) AVPlayer *player;
@end
#import "ViewController.h"
#import
#define DEGREES_TO_RADIANS(d) (d * M_PI / 180)
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//设置背景颜色
self.view.backgroundColor = [UIColor colorWithRed:0.972 green:0.134 blue:0.173 alpha:1.000];
self.view.tintColor = [UIColor whiteColor];
// Setup AVPlayer
//1.视频地址
NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"cyborg" ofType:@"m4v"];
//2.创建player对象
self.player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:moviePath]];
//3.播放
[self.player play];
//4.创建和配置AvPlayerlayer
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
playerLayer.bounds = CGRectMake(0, 0, 300, 170);
playerLayer.position = CGPointMake(210, 200);
playerLayer.borderColor = [UIColor whiteColor].CGColor;
playerLayer.borderWidth = 3.0;
playerLayer.shadowOffset = CGSizeMake(0, 3);
playerLayer.shadowOpacity = 0.80;
//5.添加透视投影,可让播放视频的图层旋转
self.view.layer.sublayerTransform = CATransform3DMakePerspective(1000);
[self.view.layer addSublayer:playerLayer];
// Set up slider used to rotate video around Y-axis
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(60, 300, 300, 23)];
slider.minimumValue = -1.0;
slider.maximumValue = 1.0;
slider.continuous = NO;
slider.value = 0.0;
[slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventTouchDragInside];
[self.view addSubview:slider];
// Spin button to spin the video around the X-axis
UIButton *spinButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
spinButton.frame = CGRectMake(0, 0, 50, 31);
spinButton.center = CGPointMake(210, 350);
[spinButton setTitle:@"Spin" forState:UIControlStateNormal];
[spinButton addTarget:self action:@selector(spinIt) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:spinButton];
}
// Animate spinning video around X-axis,视频图层围绕x轴旋转
- (void)spinIt {
CALayer *layer = [self.view.layer sublayers][0];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
animation.duration = 1.25f;
animation.toValue = @(DEGREES_TO_RADIANS(360));
[layer addAnimation:animation forKey:@"spinAnimation"];
}
// Rotate the layer around the Y-axis as slider value is changed
-(void)sliderValueChanged:(UISlider *)sender{
CALayer *layer = [self.view.layer sublayers][0];
layer.transform = CATransform3DMakeRotation([sender value], 0, 1, 0);
}
static CATransform3D CATransform3DMakePerspective(CGFloat z) {
CATransform3D t = CATransform3DIdentity;
t.m34 = - 1.0 / z;
return t;
}
- (void)dealloc {
[self.player pause];
}
@end