首页 > 其他分享 >「OC」探索CALayer:基础知识与实用技巧简要介绍

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

时间:2024-08-17 19:54:38浏览次数:11  
标签:实用技巧 layer self OC CALayer 100 属性 UIView

「OC」探索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.0
                                                  target:self
                                                selector:@selector(changeColor)
                                                userInfo:nil
                                                 repeats: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;

@end

NS_ASSUME_NONNULL_END
—————————————————————————————————————————————————————————————————————————————————————————————————————————
#import "ImageLayer.h"

@implementation ImageLayer

- (void)drawInContext:(CGContextRef)ctx {
    // Set the background color
    CGContextSetFillColorWithColor(ctx, self.background.CGColor);
    CGContextFillRect(ctx, self.bounds);
    
    if (self.image) {
        // Draw the image centered in the layer
        CGRect 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 绘制

标签:实用技巧,layer,self,OC,CALayer,100,属性,UIView
From: https://blog.csdn.net/aa2002aa/article/details/141285729

相关文章

  • JavaDoc生成文档两种方式
    JavaDoc生成文档方法一:通过命令行/***@authorzhang*@version1.0.0*@since1.8*/publicclasstest{Stringname;publicStringtest(Stringname)throwsException{returnname;}}在String下面输入/**,按Enter键在所建类中,......
  • 六. 部署分类器-preprocess-speed-compare
    目录前言0.简述1.案例运行2.代码分析2.1main.cpp2.2preprocess.cpp3.补充说明结语下载链接参考前言自动驾驶之心推出的《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考本次课程我们来学习课程第六章—部署分类器,一起来CPU端图像预......
  • coca 搭配 described in (collocates能用 神奇)
      HELP FREQ 1  THE65872  ,26613  .22504  AS22055  OF19486  THIS11477  AND11468  IS11419  (112510  A102111  ARE89012  DETAIL666......
  • nginx源码之Docker镜像制作
    1.下载nginx-1.26.2源码,并解压nginx源码下载:https://nginx.org/download/nginx-1.26.2.tar.gzmkdirdockerbuild&&cd dockerbuild wget https://nginx.org/download/nginx-1.26.2.tar.gztar-xzvf nginx-1.26.2.tar.gz2.干货Dockerfile#编译基础环境准备阶段FROMre......
  • 【Docker系列】Docker 容器时区设置指南
    ......
  • 机器学习之ROC曲线
    机器学习之ROC曲线1.TPR与FPR计算2.TPR、FPR与分类阈值的关系3.生成ROC曲线4.AUC计算参考文献本博客主要参考了https://www.evidentlyai.com/classification-metrics/explain-roc-curve。1.TPR与FPR计算真阳率TPR(TruePositiverate),又称召回率recallrate......
  • locale: Cannot set LC_CTYPE to default locale: No such file or directory locale:
    locale:CannotsetLC_CTYPEtodefaultlocale:Nosuchfileordirectorylocale:CannotsetLC_MESSAGEStodefaultlocale:Nosuchfileordirectorylocale:CannotsetLC_COLLATEtodefaultlocale:Nosuchfileordirectory 一、CannotsetLC_CTYPEtodefaul......
  • ZYNQ SoC如何读取在Windows下配置的环境变量
    在解释ZYNQSoC如何读取在Windows下配置的环境变量之前,需要澄清一点:通常,ZYNQSoC或任何嵌入式系统并不直接在Windows操作系统下运行或配置环境变量。环境变量的配置通常是在嵌入式系统的开发阶段,在开发主机(可能是运行Windows的PC)上进行的,然后通过交叉编译、生成镜像文件等方......
  • 深入探索CSS的:local-link伪类:选择指向同一文档的链接
    CSS(层叠样式表)是控制网页样式的核心语言,它允许开发者根据元素的不同状态和特性来应用样式。:local-link伪类是CSS中一个相对较少被讨论的选择器,它专门用于选择那些指向同一文档内锚点的链接。本文将详细介绍:local-link伪类的使用方式、应用场景以及如何通过它们增强网页的......
  • 全新AutoCAD安装包+CAD2025软件安装视频教程+全套构图插件+部署说明文档下载
    CAD软件是工程师、产品设计师和任何希望将设计变为现实的熟练专业人士的必备工具。也许您刚刚开始CAD设计,不想做出财务承诺,或者您是一位专业人士,需要全天候解决一些设计问题,或者您可能需要足够熟悉特定的CAD程序获得这份出色的设计工作。无论如何,幸运的是,对于专业和业......