CALayer的常见应用

一、什么是CALayer

  • 在iOS系统中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮、一个文本标签、一个文本输入框、一个图标等等,这些都是UIView。

  • 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个层。

  • 在创建UIView对象时,UIView内部会自动创建一个层(即CALayer对象),通过UIView的layer属性可以访问这个层。当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的层上,绘图完毕后,系统会将层拷贝到屏幕上,于是就完成了UIView的显示。

  • 换句话说,UIView本身不具备显示的功能,是它内部的层才有显示功能。

二、CALayer的简单使用

上面已经说过了,UIView之所以能够显示,完全是因为内部的CALayer对象。因此,通过操作这个CALayer对象,可以很方便地调整UIView的一些界面属性,比如:阴影、圆角大小、边框宽度和颜色等。

1.CALayer是被定义在QuartzCore框架中的,因此要想使用CALayer,先导入QuartzCore框架 在项目描述页面添加框架即可!

2.在项目代码中导入QuartzCore框架的主头文件 // #import <QuartzCore/QuartzCore.h>

3.通过CALayer修改UIImageView的界面属性 你也可以使用UIButton或者UILabel,这里就以UIImageView为例子

<!-- lang: cpp -->
1> 先创建一个UIImageView,添加到控制器的view中

1 UIImage *image = [UIImage imageNamed:@"lufy.png"]; 2 UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease]; 3 imageView.center = CGPointMake(100, 100); 4 [self.view addSubview:imageView];

在此输入图片描述 2> 设置阴影 1 imageView.layer.shadowColor = [UIColor grayColor].CGColor; 2 imageView.layer.shadowOffset = CGSizeMake(10, 10); 3 imageView.layer.shadowOpacity = 0.5;

  • 第1行设置阴影的颜色为灰色,注意,这里使用的是UIColor的CGColor属性,是一种CGColorRef类型的数据

  • 第2行设置阴影的偏移大小,可以看出阴影往原图的右下角偏移

  • 第3行设置阴影的不透明度为0.5,表示半透明。如果为1,代表完全不透明。

在此输入图片描述

3> 设置圆角大小 通过layer属性可以访问视图内部的CALayer对象

1 imageView.layer.cornerRadius = 10; 2 imageView.layer.masksToBounds = YES;

  • 第1行设置圆角半径为10

  • 第2行的maskToBounds=YES:可以看做是强制内部的所有子层支持圆角效果,少了这个设置,UIImageView是不会有圆角效果的

  • 注意,如果设置了maskToBounds=YES,那将不会有阴影效果 在此输入图片描述

4> 设置边框宽度和颜色 1 imageView.layer.borderWidth = 5; 2 imageView.layer.borderColor = [UIColor redColor].CGColor;

  • 第1行设置边框宽度为5

  • 第2行设置边框颜色为红色 在此输入图片描述

5> 设置旋转 imageView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);

  • 利用transform属性可以设置旋转、缩放等效果

  • M_PI_4表示四分之π,顺时针旋转45°

  • 后面的(0, 0, 1)表示Z轴这个向量,修改这个向量可以做一些三维旋转效果,你可以随便改个值试一下,比如(1, 1, 1)

  • 总体的意思是layer会绕着Z轴顺时针旋转45°,也就是在x、y平面进行旋转 在此输入图片描述

上面已经说过,UIView内部默认有个CALayer对象(层),通过layer属性可以访问这个层。要注意的是,这个默认的层不允许重新创建,但可以往层里面添加子层

  • UIView可以通过addSubview:方法添加子视图,类似地,CALayer可以通过addSublayer:方法添加子层 接下来演示一下如何添加子层:

三、添加一个简单的图层

<!-- lang: cpp -->
CALayer *myLayer = [CALayer layer];

// 设置层的宽度和高度(100x100) myLayer.bounds = CGRectMake(0, 0, 100, 100); // 设置层的位置 myLayer.position = CGPointMake(100, 100); // 设置层的背景颜色:红色 myLayer.backgroundColor = [UIColor redColor].CGColor; // 设置层的圆角半径为10 myLayer.cornerRadius = 10;

// 添加myLayer到控制器的view的layer中 [self.view.layer addSublayer:myLayer];

  • 第1行创建了一个自动释放的CALayer对象,你也可以使用经典的alloc和init方法来创建

  • 第12行将创建好的层添加到控制器的view的层中 在此输入图片描述

四、添加一个显示图片的图层

<!-- lang: cpp -->
CALayer *myLayer = [CALayer layer];

// 设置层的宽度和高度(100x100) myLayer.bounds = CGRectMake(0, 0, 100, 100); // 设置层的位置 myLayer.position = CGPointMake(100, 100); // 设置需要显示的图片 myLayer.contents = (id)[UIImage imageNamed:@"lufy.png"].CGImage; // 设置层的圆角半径为10 myLayer.cornerRadius = 10; // 如果设置了图片,需要设置这个属性为YES才有圆角效果 myLayer.masksToBounds = YES;

// 添加myLayer到控制器的view的layer中 [self.view.layer addSublayer:myLayer];

  • 在第7行设置需要显示的图片,注意,这里用的是UIImage的CGImage属性,是一种CGImageRef类型的数据

在此输入图片描述

五、为什么CALayer中使用CGColorRef和CGImageRef这2种数据类型,而不用UIColor和UIImage?

  • 首先要知道:CALayer是定义在QuartzCore框架中的;CGImageRef、CGColorRef两种数据类型是定义在CoreGraphics框架中的;UIColor、UIImage是定义在UIKit框架中的

  • 其次,QuartzCore框架和CoreGraphics框架是可以跨平台使用的,在iOS和Mac OS X上都能使用,但是UIKit只能在iOS中使用

  • 因此,为了保证可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef

  • 不过很多情况下,可以通过UIKit对象的特定方法,得到CoreGraphics对象,比如UIImage的CGImage方法可以返回一个CGImageRef

六、UIView和CALayer的选择 细心的朋友不难发现,其实前面的2个效果不仅可以通过添加层来实现,还可以通过添加UIView来实现。比如,第1个红色的层可以用一个UIView来实现,第2个显示图片的层可以用一个UIImageView来实现。 既然CALayer和UIView都能实现相同的显示效果,那究竟该选择谁好呢?

  • 其实,对比CALayer,UIView多了一个事件处理的功能。也就是说,CALayer不能处理用户的触摸事件,而UIView可以

  • 所以,如果显示出来的东西需要跟用户进行交互的话,用UIView;如果不需要跟用户进行交互,用UIView或者CALayer都可以

  • 当然,CALayer的性能会高一些,因为它少了事件处理的功能,更加轻量级

七、UIView和CALayer的其他关系

  • UIView可以通过subviews属性访问所有的子视图,类似地,CALayer也可以通过sublayers属性访问所有的子层

  • UIView可以通过superview属性访问父视图,类似地,CALayer也可以通过superlayer属性访问父层

如果两个UIView是父子关系,那么它们内部的CALayer也是父子关系。

八、隐式动画属性 每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根层)。所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动画。

  • 当对非Root Layer的部分属性进行相应的修改时,默认会自动产生一些动画效果,这些属性称为Animatable Properties(可动画属性)。

  • 列举几个常见的Animatable Properties: bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画 backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画 position:用于设置CALayer的位置。修改这个属性会产生平移动画 比如:假设一开始CALayer的position为(100, 100),然后在某个时刻修改为(200, 200),那么整个CALayer就会在短时间内从(100, 100)这个位置平移到(200, 200)

  • 我们也可以从官方文档中查询所有的Animatable Properties

九、position和anchorPoint

  • position和anchorPoint属性都是CGPoint类型的

  • position可以用来设置CALayer在父层中的位置,它是以父层的左上角为坐标原点(0, 0)

  • anchorPoint称为"定位点",它决定着CALayer身上的哪个点会在position属性所指的位置。它的x、y取值范围都是0~1,默认值为(0.5, 0.5) 1.创建一个CALayer,添加到控制器的view的layer中

    <!-- lang: cpp -->

    CALayer *myLayer = [CALayer layer]; // 设置层的宽度和高度(100x100) myLayer.bounds = CGRectMake(0, 0, 100, 100); // 设置层的位置 myLayer.position = CGPointMake(100, 100); // 设置层的背景颜色:红色 myLayer.backgroundColor = [UIColor redColor].CGColor;

// 添加myLayer到控制器的view的layer中 [self.view.layer addSublayer:myLayer];

第5行设置了myLayer的position为(100, 100),又因为anchorPoint默认是(0.5, 0.5),所以最后的效果是:myLayer的中点会在父层的(100, 100)位置 在此输入图片描述

2.若将anchorPoint改为(0, 0),myLayer的左上角会在(100, 100)位置 1 myLayer.anchorPoint = CGPointMake(0, 0); 在此输入图片描述

3.若将anchorPoint改为(1, 1),myLayer的右下角会在(100, 100)位置 1 myLayer.anchorPoint = CGPointMake(1, 1);

4.将anchorPoint改为(0, 1),myLayer的左下角会在(100, 100)位置 1 myLayer.anchorPoint = CGPointMake(0, 1);

我想,你应该已经明白anchorPoint的用途了吧,它决定着CALayer身上的哪个点会在position所指定的位置上。它的x、y取值范围都是0~1,默认值为(0.5, 0.5),因此,默认情况下,CALayer的中点会在position所指定的位置上。当anchorPoint为其他值时,以此类推。

转载于:https://my.oschina.net/panyong/blog/203146

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为下列代码实现可暂停效果: import UIKit class ViewController: UIViewController { private let radarAnimation = "radarAnimation" private var animationLayer: CALayer? private var animationGroup: CAAnimationGroup? private var opBtn: UIButton! override func viewDidLoad() { super.viewDidLoad() let first = makeRadarAnimation(showRect: CGRect(x: 120, y: 100, width: 100, height: 100), isRound: true) view.layer.addSublayer(first) opBtn = UIButton(frame: CGRect(x: 100, y: 450, width: 80, height: 80)) opBtn.backgroundColor = UIColor.red opBtn.clipsToBounds = true opBtn.setTitle("Hsu", for: .normal) opBtn.layer.cornerRadius = 10 view.addSubview(opBtn) let second = makeRadarAnimation(showRect: opBtn.frame, isRound: false) view.layer.insertSublayer(second, below: opBtn.layer) } @IBAction func startAction(_ sender: UIButton) { animationLayer?.add(animationGroup!, forKey: radarAnimation) } @IBAction func stopAction(_ sender: UIButton) { animationLayer?.removeAnimation(forKey: radarAnimation) } private func makeRadarAnimation(showRect: CGRect, isRound: Bool) -> CALayer { // 1. 一个动态波 let shapeLayer = CAShapeLayer() shapeLayer.frame = showRect // showRect 最大内切圆 if isRound { shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: showRect.width, height: showRect.height)).cgPath } else { // 矩形 shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: showRect.width, height: showRect.height), cornerRadius: 10).cgPath } shapeLayer.fillColor = UIColor.orange.cgColor // 默认初始颜色透明度 shapeLayer.opacity = 0.0 animationLayer = shapeLayer // 2. 需要重复的动态波,即创建副本 let replicator = CAReplicatorLayer() replicator.frame = shapeLayer.bounds replicator.instanceCount = 4 replicator.instanceDelay = 1.0 replicator.addSublayer(shapeLayer) // 3. 创建动画组 let opacityAnimation = CABasicAnimation(keyPath: "opacity") opacityAnimation.fromValue = NSNumber(floatLiteral: 1.0) // 开始透明度 opacityAnimation.toValue = NSNumber(floatLiteral: 0) // 结束时透明底 let scaleAnimation = CABasicAnimation(keyPath: "transform") if isRound { scaleAnimation.fromValue = NSValue.init(caTransform3D: CATransform3DScale(CATransform3DIdentity, 0, 0, 0)) // 缩放起始大小 } else { scaleAnimation.fromValue = NSValue.init(caTransform3D: CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 0)) // 缩放起始大小 } scaleAnimation.toValue = NSValue.init(caTransform3D: CATransform3DScale(CATransform3DIdentity, 1.5, 1.5, 0)) // 缩放结束大小 let animationGroup = CAAnimationGroup() animationGroup.animations = [opacityAnimation, scaleAnimation] animationGroup.duration = 3.0 // 动画执行时间 animationGroup.repeatCount = HUGE // 最大重复 animationGroup.autoreverses = false self.animationGroup = animationGroup shapeLayer.add(animationGroup, forKey: radarAnimation) return replicator } }
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值