CoreAnimation层面的动画
CALayer层(显示的基础)
- UIView核心显示功能就是依靠CALayer实现
UIView和CALayer的关系
- 1.UIView显示能力是依赖底层的CALayer实现的,每一个UIView都包换一个CALayer对对象,修改CALayer,会影响表现出来的UIView的外观
- 2.UIView与CALayer最大的不同在于,layer是不能够响应用户事件,UIView可以响应用户事件
如何获取UIView底层的那个CALayer对象
- 通过.layer属性获取
可以使用CALayer做哪些操作?
常用属性
- borderColor边框颜色
- borderWidth边框宽度
- cornerRadius圆角半径
- shadowOpacity阴影透明度
- shadowColor阴影颜色
- shadowRadius阴影半径
- shadowOffset阴影偏移量
- masksToBounds是否按layer遮罩
与尺寸和位置相关的三个重要属性
- bounds大小
- position位置
- anchorPosition锚点自身的参考点
- (void)viewDidLoad {
[super viewDidLoad];
//获取 view 中的 layer 对象
CALayer *layer = self.redView.layer;
//背景颜色
layer.backgroundColor = [UIColor greenColor].CGColor;
//设置边框宽度
layer.borderWidth = 4;
//设置边框颜色
layer.borderColor = [UIColor redColor].CGColor;
//设置圆角的 半径
// layer.cornerRadius = self.redView.bounds.size.width * 0.5;
//设置阴影 一定要先设置 阴影为不透明 默认是透明 0
layer.shadowOpacity = 1;
//设置阴影颜色
layer.shadowColor = [UIColor blackColor].CGColor;
//设置阴影的圆角
layer.shadowRadius = 10;
//设置阴影的 便宜量
layer.shadowOffset = CGSizeMake(20, 20);
//设置imageView的layer
CALayer *imageViewLayer = self.imageView.layer;
imageViewLayer.cornerRadius = self.imageView.bounds.size.height * 0.5;
imageViewLayer.borderWidth = 5;
imageViewLayer.borderColor = [UIColor lightGrayColor].CGColor;
//要按照层的边缘进行遮罩
imageViewLayer.masksToBounds = YES;
//CALyer具有容器的特性 可以相互嵌套
//创建CALayer对象
CALayer *myLayer = [CALayer layer];
myLayer.backgroundColor = [UIColor blueColor].CGColor;
// myLayer.frame = CGRectMake(0, 0, 100, 100);
//设置大小
myLayer.bounds = CGRectMake(0, 0, 100, 100);
//设置位置 当前layer 参考点(中心点) 在父layer坐标系中 的位置 默认是 0 0 点
// myLayer.position = CGPointMake(50, 50);
//设置当前 layer 参考点的位置 (锚点 默认 0.5 0.5)
// myLayer.anchorPoint = CGPointZero;
//设置 层的 旋转 (变形 是锚点操作的)
myLayer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
//将自己创建的layer 添加到 self.redView的layer中
[self.redView.layer addSublayer:myLayer];
}
创建新的Layer使用layer
- 图片CALayer
- 给contents属性赋值
- 文字层CATextLayer
- 图形层CAShapeLayer
图片Layer
-(CADisplayLink *)link {
if (!_link) {
//每刷新一次 调用一次 定时器的事件方法
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotation:)];
//手动将定时器 加入到 事件循环队列中
[_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_link.paused = YES;
}
return _link;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.link.paused = !self.link.paused;
}
-(void)rotation:(CADisplayLink*)sender {
// 5秒钟 转一圈
// 360 / 5; 求出1秒钟多少度 72
// 1秒钟调用 60次 转72度
// 每次调用 转 72/60.0
//不能用角度 因为参数 需要的是 弧度
self.imageView.layer.transform = CATransform3DRotate(self.imageView.layer.transform, angleToRadian(72/60.0), 1, 1, 1);
}
- (void)viewDidLoad {
[super viewDidLoad];
self.imageView.layer.cornerRadius = self.imageView.bounds.size.width * 0.5;
self.imageView.layer.borderWidth = 3;
self.imageView.layer.borderColor = [UIColor redColor].CGColor;
self.imageView.layer.masksToBounds = YES;
self.imageView.layer.anchorPoint = CGPointMake(0.2, 0.2);
for (NSInteger i = 0; i < 8; i++) {
CALayer *layer = [CALayer layer];
//为层添加图片内容
layer.contents = (id)[UIImage imageNamed:@"60"].CGImage;
layer.bounds = CGRectMake(0, 0, 20, self.imageView.bounds.size.height * 0.5);
layer.position = CGPointMake(self.imageView.bounds.size.width * 0.5, self.imageView.bounds.size.height * 0.5);
layer.anchorPoint = CGPointMake(0.5, 1);
layer.transform = CATransform3DMakeRotation(M_PI_4 * i, 0, 0, 1);
[self.imageView.layer addSublayer:layer];
}
}
文字及图形层
- (void)viewDidLoad {
[super viewDidLoad];
//创建文字类型的图层
CATextLayer *tLayer = [CATextLayer layer];
tLayer.string = @"这是一个文字";
tLayer.fontSize = 20;
tLayer.foregroundColor = [UIColor whiteColor].CGColor;
tLayer.backgroundColor = [UIColor blackColor].CGColor;
tLayer.bounds = CGRectMake(0, 0, 200, 40);
tLayer.position = CGPointMake(100, 100);
tLayer.anchorPoint = CGPointZero;
//将文字层 添加到 self.view.layer 上
[self.view.layer addSublayer:tLayer];
//图形类型的图层
CAShapeLayer *sLayer = [CAShapeLayer layer];
self.sLayer = sLayer;
sLayer.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 100, 50) cornerRadius:10].CGPath;
sLayer.strokeColor = [UIColor redColor].CGColor;
sLayer.fillColor = [UIColor whiteColor].CGColor;
sLayer.backgroundColor = [UIColor blackColor].CGColor;
sLayer.bounds = CGRectMake(0, 0, 200, 200);
sLayer.position = CGPointMake(50, 250);
sLayer.anchorPoint = CGPointZero;
//添加边框
sLayer.borderColor = [UIColor blueColor].CGColor;
sLayer.borderWidth = 5;
sLayer.cornerRadius = 10;
//将图形层 添加到 self.view.Layer 上
[self.view.layer addSublayer:sLayer];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// arc4random_uniform 取出 0 ~ x-1
self.sLayer.borderWidth = arc4random_uniform(25);
self.sLayer.cornerRadius = arc4random_uniform(30);
}
CALayer的很多属性都有隐式动画,在修改该属性时,会自动出现动画效果,可以通过查看头文件中,属性上面出现animatable这样的说明时,意味可以有隐式动画
CAAnimation动画
- CA的动画,只能施加在CALayer上
- CA动画与UIView动画最大的一个区别:
- CA动画是假的,视图看着好像位置改变了,但其实没有变
- UIView动画中,由于明确的设定了动画结束时视图的状态,所以视图的数据会随着动画的结束而真的改变
CAAnimation的子类之一
- CABasicAnimation基础动画
CAAnimation的子类之二
- CAAnimationGroup动画组
CAAnimation的子类之三
- CAKeyFrameAnimation关键帧动画
CAAnimation
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// [self position];
// [self transform];
// [self groupAnimation];
[self keyFrameAnimation];
}
-(void)position {//位移动画
CABasicAnimation *basicAnim = [CABasicAnimation animation];
//位移position 缩放scale 旋转 rotation
//使用KVC的方式为对象赋值,说明要改的属性名是什么
basicAnim.keyPath = @"position";
basicAnim.fromValue = [NSValue valueWithCGPoint:CGPointMake(50, 50)];
//toValue 是 到 50 300的位置上
basicAnim.toValue = [NSValue valueWithCGPoint:CGPointMake(50, 300)];
//byValue 在自身基础上 移动 50 300
// basicAnim.byValue = [NSValue valueWithCGPoint:CGPointMake(50, 300)];
//动画结束时 不把动画 从视图上 移除 如果需要固定动画结束时视图的位置 必须 再配合 fillMode 该属性一起使用
basicAnim.removedOnCompletion = NO;
/*
kCAFillModeForwards 当动画结束后,layer会一致保持着动画最后的状态
kCAFillModeBackwards 在动画开始前,只需要将动画加入一个Layer,layer便立即进入动画的初始状态并等待运行动画
kCAFillModeBoth 上面两种效果叠加在一起
kCAFillModeRemoved (默认) 当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
*/
basicAnim.fillMode = kCAFillModeBoth;
//设置动画 开始前等待时间
basicAnim.beginTime = CACurrentMediaTime() + 3;
//设置动画的 相关属性
//动画持续时间
basicAnim.duration = 2;
//动画重复次数 一直重复只是给以非常大的值
// basicAnim.repeatCount = MAXFLOAT;
basicAnim.repeatCount = 1;
//运行动画 注意:CA动画只能使用 CALayer对象运行
[self.imageView.layer addAnimation:basicAnim forKey:nil];
}
-(void)transform {//变形动画
CABasicAnimation *transformAnim = [CABasicAnimation animation];
// transformAnim.keyPath = @"transform";
// transformAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.2, 1)];
//动画只能执行 最后设置的 keyPath ,如果需要同时执行只能依赖 CAAnimation 的另外一个子类 CAAnimationGrop
transformAnim.keyPath = @"transform.scale";
transformAnim.toValue = @1.2;
transformAnim.keyPath = @"transform.rotation";
transformAnim.toValue = @(M_PI * 2);
transformAnim.duration = 1;
transformAnim.repeatCount = MAXFLOAT;
[self.imageView.layer addAnimation:transformAnim forKey:nil];
}
-(void)groupAnimation {
CABasicAnimation *positionAnim = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnim.toValue = @(self.imageView.center.y + 200);
CABasicAnimation *transformAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
transformAnim.toValue = @(M_PI);
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = @[positionAnim, transformAnim];
group.duration = 3;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[self.imageView.layer addAnimation:group forKey:nil];
}
-(void)keyFrameAnimation {//关键帧动画
CAKeyframeAnimation *keyFrameAnim = [CAKeyframeAnimation animation];
keyFrameAnim.keyPath = @"position";
// //设置中间行进的路线的关键值
// keyFrameAnim.values = @[
// [NSValue valueWithCGPoint:CGPointMake(50, 50)],
// [NSValue valueWithCGPoint:CGPointMake(200, 200)],
// [NSValue valueWithCGPoint:CGPointMake(60, 300)],
// [NSValue valueWithCGPoint:CGPointMake(150, 80)]];
keyFrameAnim.path = [UIBezierPath bezierPathWithRect:CGRectMake(80, 80, 200, 300)].CGPath;
keyFrameAnim.duration = 3;
keyFrameAnim.removedOnCompletion = NO;
keyFrameAnim.fillMode = kCAFillModeForwards;
[self.imageView.layer addAnimation:keyFrameAnim forKey:nil];
}
2.布局Layout
什么是布局
- 是指在一个视图中,如何摆放它的子视图(设置子视图的位置和大小)
可能导致屏幕尺寸大小发生变化的原因
- a.屏幕方向(横竖屏)
- b.设备不同(3.5寸,4寸,4.7寸,5.5寸)
- c.状态栏
- 隐藏
- 特殊的状态栏
– 来电时绿色的状态栏
– 开启个人热点蓝色的状态栏
– 录音时红色的状态栏
- d.各种bar
- NaviationBar:竖屏时64点高横屏时52个点高
- ToolBar:44/32个点
- TabBar:49个点
- e.键盘弹起和收回
如何布局?
- 方法一:纯代码布局(古老的方法)
- 理念:当屏幕发生变化时,自动执行一段代码,在代码中根据新的屏幕大小重新计算各个视图的frame,从而达到重新定位的目的
- 特点:功能强大,非常繁琐
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *myView1;
@property (weak, nonatomic) IBOutlet UIView *myView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIView *greenView1;
@property (weak, nonatomic) IBOutlet UIView *greenView2;
@property (weak, nonatomic) IBOutlet UIView *greenView3;
@end
@implementation ViewController
//该方法在view加载完会调用一次, 在屏幕发生旋转也会自动调用
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat space20 = 20;
CGFloat space10 = 10;
CGFloat viewWidth = (self.view.bounds.size.width - space20 * 2 - space10) * 0.5;
CGFloat viewHeight = 40;
CGFloat viewX = space20;
CGFloat viewY = space20;
CGFloat greenViewWidth = 20;
CGFloat greenViewHeight = 20;
CGRect frame = CGRectMake(viewX, viewY, viewWidth, viewHeight);
self.myView1.frame = frame;
//设置 第二个view的frame
frame.origin.x += viewWidth + space10;
self.myView2.frame = frame;
//设置imageview的frame
frame.origin.x = space20;
frame.origin.y += viewHeight + space10;
frame.size.width = self.view.bounds.size.width - space20 * 2;
frame.size.height = self.view.bounds.size.height - space20 * 2 - space10 * 2 - greenViewHeight - viewHeight;
self.imageView.frame = frame;
//设置小绿view1的frame
frame.origin.x = self.view.bounds.size.width - (space20 + greenViewWidth);
frame.origin.y = self.view.bounds.size.height - space20 - greenViewHeight;
frame.size.width = greenViewWidth;
frame.size.height = greenViewHeight;
self.greenView1.frame = frame;
//设置小绿view2的frame
frame.origin.x -= greenViewWidth + space10;
self.greenView2.frame = frame;
//设置小绿view3的frame
frame.origin.x -= greenViewWidth + space10;
self.greenView3.frame = frame;
}
作者:shuan9999 发表于2016/9/26 19:44:35 原文链接
阅读:206 评论:0 查看评论