「OC」探索CALayer:基础知识与实用技巧简要介绍

devtools/2024/10/15 18:30:19/

「OC」探索CALayer:基础知识与实用技巧简要介绍

文章目录

  • 「OC」探索CALayer:基础知识与实用技巧简要介绍
    • 前言
    • 认识CALayer
      • CALayer的相关属性
    • UIView和CALayer
      • 区别
      • 联系
      • 创建UIView和CALayer的原因
    • 开始创建CALayer
      • 视图层级
      • CALayers 和 Sublayers
      • position与anchorPoint(锚点)
      • CGImage和CGColor
      • 设置旋转
      • 裁切
      • border属性
    • 隐式动画
    • 自定义CALayer
      • 重写CALayer的子类
      • 实现CALayer协议方法
    • 参考文章

前言

在顺利完成暑假之中的任务之后,终于可以学习一点之前一直没有时间学习的内容啦。上一片文章写到「iOS」自定义Modal转场——抽屉视图的实现,我们已经成功的实现了抽屉视图,接下来是要实现cell之中的圆角。我看到要想实现这个圆角cell,需要OC之中的图形绘制CALayer的内容,于是我继续对CALayer进行学习,如果篇幅过长那么会将圆角cell的实现放到后面来。

认识CALayer

CALayer是属于Core Animation,简单说就是呈现内容和动画的层。

在iOS之中我们能够看到的基本上都是UIView,比如一个按钮,一个文本框等等…

那么这些UIView能够被显示在屏幕之中被我们看到,其实是就是由于这个UIView的layer属性(也就是CALayer对象),当这个UIView需要倍显示在屏幕之上的时候,就会通过调用drawRect:这个方法,访问图层进行绘制,可以说UIView本身是没有显示的功能,只有它内部的层级才具有显示功能。

我们可以通过以下方法获取UIView之中的图层

CALayer *myLayer = myView.layer;

CALayer的相关属性

4408163-f04410c51fec8d39.png-3

可以看到CALayer有着丰富的属性可以用来:

  • 调整图层的大小和位置
  • 调整图层的背景颜色
  • 修改图层的内容 (一个图片,或者是用 CoreGraphics 绘制的东西)
  • 图层是否圆角
  • 添加黑色投影
  • 添加描边的边框

UIView和CALayer

区别

CAlayerUIView最大的不同是CALayer不处理用户的交互。CALayer并不清楚具体的响应链(iOS通过视图层级关系用来传送触摸事件的机制),于是它并不能够响应事件,即使它提供了一些方法来判断是否一个触点在图层的范围之内。

UIApplicationUIViewControllerUIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。在 UIResponder中定义了处理各种事件和事件传递的接口, 而 CALayer直接继承 NSObject,并没有相应的处理事件的接口。

如果显示出来的东西需要跟用户进行交互的话,那我们肯定要用UIView;如果不需要跟用户进行交互,我们尽量使用`CALayer,因为它少了事件处理的功能,性能会高一些

联系

2144507-d32bcab32145e840.png

代理关系:UIView 实现了 CALayerDelegate 协议,这意味着当系统需要绘制 CALayer 的内容时,实际上是 UIView 在幕后调用相关方法进行绘制。这种设计使得开发者可以在 UIView 的上下文中定制内容绘制逻辑,同时利用 CALayer 的高效渲染能力。

属性映射:许多 UIView 的视觉属性(如背景色、边框等)实际上是对内部 CALayer 相关属性的封装。更改 UIView 的这些属性时,实际上是在更改其 CALayer 的对应属性。

创建UIView和CALayer的原因

我们都知道,UIView和CALayer为两个平行的层级关系,那么为什么要这么设计呢?

这里我直接引用大佬博客之中的内容:

原因在于要做职责分离,这样也能避免很多重复代码。在iOS和Mac OS两个平台上,事件和用户交互有很多地方的不同,基于多点触控的用户界面和基于鼠标键盘有着本质的区别,这就是为什么iOS有UIKit和UIView,但是Mac OS有AppKit和NSView的原因。他们功能上很相似,但是在实现上有着显著的区别。

绘图,布局和动画,相比之下就是类似Mac笔记本和桌面系列一样应用于iPhone和iPad触屏的概念。把这种功能的逻辑分开并应用到独立的Core Animation框架,苹果就能够在iOS和Mac OS之间共享代码,使得对苹果自己的OS开发团队和第三方开发者去开发两个平台的应用更加便捷。

开始创建CALayer

我们先创建一个CALayer并且把它加入到视图控制器之中,然后我们再进行相关内容的讲解

- (void)viewDidLoad {[super viewDidLoad];self.layer = [[CALayer alloc] init];//背景设置self.layer.backgroundColor = [UIColor redColor].CGColor;//布局self.layer.bounds = CGRectMake(0, 0, 100, 100);self.layer.position = CGPointMake(100, 100);self.layer.anchorPoint = CGPointMake(0, 0);//旋转self.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);//设置border属性self.layer.borderWidth = 4;self.layer.borderColor = [UIColor purpleColor].CGColor;//裁切self.layer.cornerRadius = 10.0;self.layer.masksToBounds = YES;// 将layer添加到图层[self.view.layer addSublayer:self.layer];
}

image-20240817185029038

视图层级

我们从视图层级的角度来看,其实不难发现他没有被单独作为一个模块列出

image-20240817002653997

CALayers 和 Sublayers

就像 UIView 有很多 subview 一样, CALayer 也有它的 sublayer

视图树中每一个 view 的根 layer 根据视图关系, 形成相同关系的 layer 树, 同时每一个根 layer 还可以有自己的 sublayer, 如下图所示:

img

position与anchorPoint(锚点)

  • position属性决定该控件在父控件中的位置,以父控件的左上角为原点
  • anchorPoint属性决定该控件上的哪个点位于position位置

若position为(100, 100),anchorPoint为(0, 0 ),如图
img

若position为(100, 100),anchorPoint为(0.5, 0.5),如图
img

当然CALayer还是可以使用frame进行布局,只是如果使用CALayer的属性进行布局在灵活性方面则更占优

CGImage和CGColor

CGImage 是 Core Graphics 框架中用于表示图像的类。它提供了对图像数据的低级别控制,适用于图像处理、渲染和绘制。

用途: CGImage 主要用于表示和操作位图图像数据。它是 UIImage 的底层表示形式,能够提供直接的图像数据访问和操作。

CGColor 是 Core Graphics 框架中用于表示颜色的类。它用于描述颜色的具体值,包括色彩空间、颜色分量等。

用途: CGColor 用于在 Core Graphics 和 Core Animation 中指定颜色。它是 UIColor 的底层表示形式,用于图层的背景色、边框色等。

我们不用先前我们所熟知的UIColor和UIImage是因为,他们被定义在UIKit.h的框架之中的,而CALayer是QuartzCore框架的内容。

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

设置旋转

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

CATransform3D CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z);

参数说明

  • angle: 旋转的角度,以弧度为单位。可以使用 M_PIM_PI / 180 将角度转换为弧度。(M_PI 即为 360°)
  • x, y, z: 旋转轴的坐标分量。决定了围绕哪个轴旋转:
    • 如果 x 为 1,y 为 0,z 为 0,则围绕 X 轴旋转。
    • 如果 x 为 0,y 为 1,z 为 0,则围绕 Y 轴旋转。
    • 如果 x 为 0,y 为 0,z 为 1,则围绕 Z 轴旋转。

裁切

另外当 layer 中的绘制内容超过其 frame 的边界时, 可以通过 masksToBounds 属性来决定是否绘制边界以外的内容. 而 view 的 clipsToBounds 属性实际就是在设置 layer 的 maskToBounds 属性. 默认情况下设置为 false, 即要绘制超过边界的内容.

    self.layer.cornerRadius = 10.0;self.layer.masksToBounds = YES;

border属性

border即为

//设置border属性
imageLayer.borderWidth = 2;
imageLayer.borderColor = [UIColor purpleColor].CGColor;

隐式动画

为了探究CALayer自带的隐式动画,我自己写了一个好玩的内容

#import "ViewController.h"@interface ViewController ()
@property (nonatomic, strong) CALayer *layer;
@property (nonatomic, strong) UIView *views;
@property (nonatomic, strong) NSTimer *timer;
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.layer = [[CALayer alloc] init];self.layer.backgroundColor = [UIColor redColor].CGColor;self.layer.bounds = CGRectMake(0, 0, 100, 100);self.layer.position = CGPointMake(100, 100);self.layer.anchorPoint = CGPointMake(0, 0);self.layer.cornerRadius = 10.0;self.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);[self.view.layer addSublayer:self.layer];self.views = [[UIView alloc] init];self.views.backgroundColor = [UIColor redColor];self.views.frame = CGRectMake(50, 250, 100, 100);[self.view addSubview:self.views];self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0target:selfselector:@selector(changeColor)userInfo:nilrepeats:YES];
}- (void)changeColor {// 生成随机颜色CGFloat red = arc4random_uniform(256) / 255.0;CGFloat green = arc4random_uniform(256) / 255.0;CGFloat blue = arc4random_uniform(256) / 255.0;self.layer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;self.views.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
}
@end

通过动图我们可以看到,我们在没有添加任何动画的情况下CALayer,在颜色发生变化时,会自动产生动画,以下是代码运行时的变化过程。

每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根层)。所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动画。我们对UIView的属性修改时时不会产生默认动画,而对单独 layer属性直接修改会,这个默认动画的时间缺省值是0.25s.

当对非Root Layer的部分属性进行相应的修改时,默认会自动产生一些动画效果:

  • bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画
  • backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画
  • position:用于设置CALayer的位置。修改这个属性会产生平移动画

Aug-17-2024 09-37-22

自定义CALayer

重写CALayer的子类

我们可以通过创建CALayer的子类来描绘我们想要实现的layer,示例如下:

#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN@interface ImageLayer : CALayer@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIColor *background;@endNS_ASSUME_NONNULL_END
—————————————————————————————————————————————————————————————————————————————————————————————————————————
#import "ImageLayer.h"@implementation ImageLayer- (void)drawInContext:(CGContextRef)ctx {// Set the background colorCGContextSetFillColorWithColor(ctx, self.background.CGColor);CGContextFillRect(ctx, self.bounds);if (self.image) {// Draw the image centered in the layerCGRect imageRect;imageRect.size = self.image.size;imageRect.origin.x = (CGRectGetWidth(self.bounds) - imageRect.size.width) / 2;imageRect.origin.y = (CGRectGetHeight(self.bounds) - imageRect.size.height) / 2;CGContextDrawImage(ctx, imageRect, self.image.CGImage);}
}@end
—————————————————————————————————————————————————————————————————————————————————————————————————————————
- (void)viewDidLoad {[super viewDidLoad];ImageLayer *imagelayer = [ImageLayer layer];imagelayer.image = [UIImage imageNamed:@"back3.jpeg"];imagelayer.background = [UIColor yellowColor];imagelayer.frame = CGRectMake(50, 50, 200, 400);[imagelayer setNeedsDisplay];[self.view.layer addSublayer:imagelayer];
}

通过运行代码,我们可以获得以下CALayer

image-20240817114908445

实现CALayer协议方法

//创建图层
CALayer *imageLayer = [[CALayer alloc] init];
//设置代理
imageLayer.delegate = self;
imageLayer.bounds = CGRectMake(0, 0, 100, 100);
imageLayer.position = CGPointMake(100, 200);
[imageLayer setNeedsDisplay];
[self.view.layer addSublayer:imageLayer];

实现代理方法

- (void)drawLayer:(nonnull CALayer *)layer inContext:(nonnull CGContextRef)ctx
{//通过绘图方法绘制内容
}

参考文章

iOS动画篇_CALayer这些牛逼的子类你造吗

读 iOS核心动画高级技巧

CALayer_超经典的阐述原理

详解CALayer 和 UIView的区别和联系

读书笔记: iOS Layer 绘制


http://www.ppmy.cn/devtools/97914.html

相关文章

CI/CD

目录 1.什么是CI/CD? 2.Gitlab仓库部署 3.部署Jenkins 3.1 使用jenkins拉取代码 3.2 对代码进行编译、打包 4.部署tomcat服务器 1.什么是CI/CD? 通俗来说就是启动一个服务&#xff0c;能够监听代码变化&#xff0c;然后自动执行打包&#xff0c;发布等流程: CICD 是持…

通过Docker部署Synapse服务器

今天我们在阿贝云免费服务器上进行部署测试。阿贝云免费服务器&#xff0c;简直就是IT界的一颗明星&#xff01;1核CPU、1G内存、10G硬盘、5M带宽&#xff0c;简直就是一个不错的免费服务器选择。 首先&#xff0c;让我们简要介绍一下使用到的Docker和Synapse软件。Docker是一…

某系统存在任意账户凭据窃取漏洞

世人都晓神仙好&#xff0c;惟有功名忘不了&#xff01;古今将相今何在&#xff1f;荒冢一堆草没了。 漏洞描述 某系统存在任意账户凭据窃取漏洞&#xff0c;攻击者使用任意账号登录后访问特殊的Url即可获取所有用户的账号和密码 漏洞复现 登录后台(存在访客用户默认账号密…

美股收涨,半导体板块领涨;苹果iPhone出货预测上调

市场概况 在昨夜的交易中&#xff0c;美股三大股指全线收涨。道琼斯工业平均指数上涨1.39%&#xff0c;纳斯达克综合指数上涨2.34%&#xff0c;标准普尔500指数上涨1.61%。值得注意的是&#xff0c;英伟达股票涨幅近4%&#xff0c;推动了科技股的整体表现。美国十年期国债收益…

无人机航拍与ArcGIS融合实战:从地表观测到空间数据可视化的全方位指南!无人机图像拼接数据处理与分析、可视化与制图

目录 第一章 无人机航拍基本流程、航线规划与飞行实践 第二章 无人机图像拼接软件的学习与操作实践 第三章 无人机图像拼接典型案例详解 第四章 无人机图像拼接数据在GIS中的处理与分析 第五章 无人机图像拼接数据在GIS中的可视化与制图 第六章 综合案例:无人机航拍植被动…

华为HCIP证书好考吗?详解HCIP证书考试难易程度及备考策略!

华为认证体系主要分为三个层次&#xff1a;HCIA(Huawei Certified ICT Associate)&#xff0c;HCIP(Huawei Certified ICT Professional)和HCIE(Huawei Certified Internetwork Expert)。作为中级认证&#xff0c;HCIP证书主要面向具备一定技术基础和项目实践能力的专业人士。在…

React+Vis.js(05):vis.js的节点的点击事件

文章目录 需求实现思路抽屉实现完整代码需求 双击节点,弹出右侧的“抽屉”,显示节点的详细信息 实现思路 vis.network提供了一个doubleClick事件,代码如下: network.on(doubleClick, function (properties) {// console.log(nodes);let id = properties

分布式ID-一窥雪花算法的原生实现问题与解决方案(CosId)

分布式ID-雪花算法的问题与方案&#xff08;CosId&#xff09; 基本原理 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url%E5%88%86%E5%B8%83%E5%BC%8FID-%E9%9B%AA%E8%8A%B1%E7%AE%9…