Core Animation学习笔记—第二节Setting up Layer Objects

各位iOS开发大佬们好:
我是一名swift+swiftUI栈的iOS小白,目前还在上大三,最近准备实习,面试的过程中发现现在大公司很多还在用OC + UIKit的技术栈,OC我还在考虑要不要学,目前想先把UIKit学完,这是我在官网学习UIKit英文文档时摘录的本人认为的重点,如果你们也觉得对你们有用的话欢迎持续关注,我大概一天更一节,有事除外。格式什么的我也就不做了,翻译都是我自己翻译的,哪里不对欢迎在评论区指正,感谢各位大佬支持

今天2021年12月2日
这一章叫做Setting up Layer Objects

iOS默认自动启用layer,但在OS X中还是需要显式的启用它以获得更好的性能表现
Link against the QuartzCore framework. (iOS apps must link against this framework only if they use Core Animation interfaces explicitly.)
Enable layer support for one or more of your NSView objects by doing the following:
For views you create programmatically, call the view’s setWantsLayer: method and pass a value of YES to indicate that the view should use layers.
在OS X中需要做以下工作来显式启用Layer
与QuartzCore链接
调用setWantsLayer: 方法,传入一个YES来启用你NSView对象的layer

可以更换与视图关联的layer类型以获得更方便的操作和可能更好的性能

在iOS中可以通过重写视图的layerclass方法为视图返回一个其他类型的layer
以下三种情况是你可能会去更改layer类型的

Your view draws content using Metal or OpenGL ES, in which case you would use a CAMetalLayer or CAEAGLLayer object.
There is a specialized layer class that offers better performance.
You want to take advantage of some specialized Core Animation layer classes, such as particle emitters or replicators.
视图使用Metal或OpenGL ES绘图时,可能会需要CAMetalLayer或CAEAGLLayer对象
其他提供更高性能的layer类型
使用一些专用CALayer例如particle emitters 或者 replicators

通过重写NSView的makeBackingLayer方法来更改默认layer类,实现时创建并返回你需要的layer类型

A layer-hosting view is an NSView object for which you create and manage the underlying layer object yourself. You might use layer hosting in situations where you want to control the type of layer object associated with the view. For example, you might create a layer-hosting view so that you can assign a layer class other than the default CALayer class. You might also use it in situations where you want to use a single view to manage a hierarchy of standalone layers.

托管图层视图是一个NSView对象,你需要自己创建并管理底层layer对象,在你需要控制视图layer的类型时,或在您想使用单个视图来管理独立图层的层次结构的情况下可以使用它。

When you call the setLayer: method of your view and provide a layer object, AppKit takes a hands-off approach to that layer. Normally, AppKit updates a view’s layer object but in the layer-hosting situation it does not for most properties.
当调用视图的setLayer:方法并提供图层对象时,AppKit不会对layer进行操作。AppKit会更新视图的图层对象,但在图层托管的情况下,大多数属性不会更新视图的图层对象。

If you choose to host layers yourself, you must set the contentsScale property yourself and provide high-resolution content at appropriate times.
如果选择自己控制layer,你需要自己设置contentsScale 属性,并在任何时候提供高分辨率的内容
CALayer是所有layer的基类,以下是衍生layer

在这里插入图片描述

layer的content其实就是包含可视数据的位图
你可以通过以下三种方法之一为位图提供可视数据
Assign an image object directly to the layer object’s contents property. (This technique is best for layer content that never, or rarely, changes.)
Assign a delegate object to the layer and let the delegate draw the layer’s content. (This technique is best for layer content that might change periodically and can be provided by an external object, such as a view.)
Define a layer subclass and override one of its drawing methods to provide the layer contents yourself. (This technique is appropriate if you have to create a custom layer subclass anyway or if you want to change the fundamental drawing behavior of the layer.)
直接往contents属性里放一个image对象(一般用于几乎不再更改视图内容的情况)
做一个代理对象,让代理对象完成内容绘制(一般用于content可能由外部对象比如view构成并且会随时更改的情况)
定义一个layer子类,并重写其中一个drawing方法提供layer内容(一般用于需要动态改变content或改变layer的绘制行为的情况)

对于第一种方法:
layer会直接使用你提供的image对象而不会深拷贝以节省内存使用,你提供的image必须是CGImageRef(在OS X中为NSImage)类型,提供的image分辨率必须和屏幕分辨率相匹配,对于Retina displays,你需要调整视图的contentsScale 属性
对于第二种方法:
If your delegate implements the displayLayer: method, that implementation is responsible for creating a bitmap and assigning it to the layer’s contents property.
If your delegate implements the drawLayer:inContext: method, Core Animation creates a bitmap, creates a graphics context to draw into that bitmap, and then calls your delegate method to fill the bitmap. All your delegate method has to do is draw into the provided graphics context.
如果你两种都实现了的话那么layer只会调用displayLayer方法

A layer-backed view automatically makes itself the delegate of its layer and implements the needed delegate methods, and you should not change that configuration. Instead, you should implement your view’s drawRect: method to draw your content.
In OS X v10.8 and later, an alternative to drawing is to provide a bitmap by overriding the wantsUpdateLayer and updateLayer methods of your view. Overriding wantsUpdateLayer and returning YES causes the NSView class to follow an alternate rendering path. Instead of calling drawRect:, the view calls your updateLayer method, the implementation of which must assign a bitmap directly to the layer’s contents property. This is the one scenario where AppKit expects you to set the contents of a view’s layer object directly.
View自动代理它的layer并且实现必要的代理方法,你应该实现view的drawRect方法绘制内容而不是更改代理方法
对于OS X v10.8之后的系统版本,通过重写视图的wantsUpdateLayer 和 updateLayer 方法提供位图,重写wantsUpdateLayer 返回YES使NSView类按照新的渲染路径渲染内容,视图的updateLayer方法必须直接为图层的content属性分配位图
对于第三种方法:
不常用,一般用于自定义layer时,通过以下两种方法绘制layer内容
Override the layer’s display method and use it to set the contents property of the layer directly.
Override the layer’s drawInContext: method and use it to draw into the provided graphics context.
Which method you override depends on how much control you need over the drawing process. The display method is the main entry point for updating the layer’s contents, so overriding that method puts you in complete control of the process. Overriding the display method also means that you are responsible for creating the CGImageRef to be assigned to the contents property. If you just want to draw content (or have your layer manage the drawing operation), you can override the drawInContext: method instead and let the layer create the backing store for you.
以上两种方法中如果你想要控制更新视图内容的过程,用display,如果你仅想绘制内容,用drawInContext
contentsGravity属性匹配内容和layer的尺寸
The values you can assign to the contentsGravity property are divided into two categories:
The position-based gravity constants allow you to pin your image to a particular edge or corner of the layer’s bounds rectangle without scaling the image.
The scaling-based gravity constants allow you to stretch the image using one of several options, some of which preserve the aspect ratio and some of which do not
contentsGravity属性可赋值的两种类型,一种是基于位置的,一种是基于伸缩的
设置合适的contentsScale属性来适配不同分辨率的内容,默认值为1.0,如果是Retina Display的话设置2.0,只在直接将位图赋值给layer的情况下使用即可,其他情况都会自动设置

在这里插入图片描述
在这里插入图片描述

the position-based gravity constants affect the way image representations are chosen from an NSImage object assigned to the layer. Because these constants do not cause the image to be scaled, Core Animation relies on the contentsScale property to pick the image representation with the most appropriate pixel density
基于位置的contentsGravity参数会影响image的representation从layer的NSImage对象中选择的方式。因为这类基于位置的参数不会引起图像拉伸,Core Animation依赖contentsScale属性匹配最合适的像素密度来显示图像
the layer’s delegate can implement the layer:shouldInheritContentsScale:fromWindow: method and use it to respond to changes in the scale factor. AppKit automatically calls that method whenever the resolution for a given window changes, possibly because the window moved between a standard-resolution and high-resolution screens. Your implementation of this method should return YES if the delegate supports changing the resolution of the layer’s image. The method should then update the layer’s contents as needed to reflect the new resolution
layer的代理可以通过实现layer:shouldInheritContentsScale:fromWindow:方法对scale factor中的改变做出响应,APPKit每当屏幕分辨率改变时会自动调用该方法,通过返回YES来使代理支持改变layer中image的分辨率,之后更新为新分辨率内容
Layer有自己独立于内容的背景色,边框等一系列装饰属性,边框渲染在内容上方,背景色渲染在layer层上,关系如下
在这里插入图片描述

You can use any type of color for the background of a layer, including colors that have transparency or use a pattern image. When using pattern images, though, be aware that Core Graphics handles the rendering of the pattern image and does so using its standard coordinate system, which is different than the default coordinate system in iOS. As such, images rendered on iOS appear upside down by default unless you flip the coordinates.
背景色可以为任何颜色或指定的image,但image将由CG在其标准坐标下渲染,与iOS坐标系统相反,所以如果不翻转坐标系渲染结果将会颠倒
如果layer有圆角,那么禁止将其标记为不透明
Because it involves applying a transparency mask, the corner radius does not affect the image in the layer’s contents property unless the masksToBounds property is set to YES. However, the corner radius always affects how the layer’s background color and border are drawn.
Layer圆角不会影响其内容,可以通过设置masksToBounds属性为YES使内容同步圆角
使用阴影时offset注意当前环境坐标系统
在这里插入图片描述

When adding shadows to a layer, the shadow is part of the layer’s content but actually extends outside the layer’s bounds rectangle. As a result, if you enable the masksToBounds property for the layer, the shadow effect is clipped around the edges. If your layer contains any transparent content, this can cause an odd effect where the portion of the shadow directly under your layer is still visible but the part extending beyond your layer is not. If you want a shadow but also want to use bounds masking, you use two layers instead of one. Apply the mask to the layer containing your content and then embed that layer inside a second layer of the exact same size that has the shadow effect enabled.
阴影效果将会延伸到layer外,所以尽量不使用masksToBounds切割,如果必须使用,那么可以用两层layer,一层用来做阴影,一层用来使用masksToBounds

Filters Add Visual Effects to OS X Views
In OS X apps, you can apply Core Image filters directly to the contents of your layers. You might do this to blur or sharpen your layer’s contents, to change the colors, to distort the content, or to perform many other types of operations. For example, an image processing program might use these filters to modify an image nondestructively while a video editing program might use them to implement different types of video transition effects. And because the filters are applied to the layer’s content in hardware, rendering is fast and smooth.
Note: You cannot add filters to layer objects in iOS.
For a given layer, you can apply filters to both the foreground and background content of the layer. The foreground content consists of everything that the layer itself contains, including the image in its contents property, its background color, its border, and the content of its sublayers. The background content is the content that is directly under the layer but not actually part of the layer itself. The background content of most layers is the content of its immediate superlayer, which may be wholly or partially obscured by the layer. For example, you might apply a blur filter to the background content when you want the user to focus on the layer’s foreground content.
You specify filters by adding CIFilter objects to the following properties of your layer:
The filters property contains an array of filters that affect the layer’s foreground content only.
The backgroundFilters property contains an array of filters that affect the layer’s background content only.
The compositingFilter property defines how the layer’s foreground and background content are composited together.
To add a filter to a layer, you must first locate and create the CIFilter object and then configure it before adding it to your layer. The CIFilter class includes several class methods for locating the available Core Image filters, such as the filterWithName: method. Creating the filter is only the first step, though. Many filters have parameters that define how the filter modifies an image. For example, a box blur filter has an input radius parameter that affects the amount of blur that is applied. You should always provide values for these parameters as part of the filter configuration process. However, one common parameter that you do not need to specify is the input image, which is provided by the layer itself.
When adding filters to layers, it is best to configure the filter parameters prior to adding the filter to the layer. The main reason for doing so is that once added to the layer, you cannot modify the CIFilter object itself. However, you can use the layer’s setValue:forKeyPath: method to change filter values after the fact.
这部分我不知道怎么翻,filter是过滤的意思,但我觉得过滤器有点奇怪,我暂时把它翻成特效吧
特效只有OS X上有,iOS上没有
通过给layer的以下属性添加CIFilter对象来指定特效
filter属性包含了一个只对layer的foreground内容有效的filter数组
backgroundfilter属性包含了一个只对layer的background内容有效的filter数组
compositiongFilter属性定义了前后背景特效的组合方式
最好在Filter被添加进来之前进行配置,因为一旦filter被添加进来,不能直接修改CIFilter对象,但可以通过setValue:forKeyPath: 方法动态更改
OS X的重绘原则决定了性能
Each view defines a layerContentsRedrawPolicy method that returns the redraw policy for the view’s layer. You set the policy using the setLayerContentsRedrawPolicy: method. To preserve compatibility with its traditional drawing model, AppKit sets the redraw policy to NSViewLayerContentsRedrawDuringViewResize by default. However, you can change the policy to any of the values
每个视图都定义了一个 layerContentsRedrawPolicy 方法返回其layer的重绘原则,你可以通过setLayerContentsRedrawPolicy: 方法编写重绘原则,为了保持与其传统绘图模型的兼容性,AppKit默认将重绘策略设置为NSViewLayerContentsRedrawDuringViewResize。你可以调整为下表中的任一原则
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Programmer_Roy/article/details/121657658