版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.01.22 |
前言
在苹果的API文档中,有很多属性和方法我们用的不是很多,所以很容易忽略和出错,下面我就用这一个专题专门说一些不常用的API接口,下面开始。感兴趣的可以参考前面几篇文章。
1. 容易忽略的那些小点总结 (一) —— UIView UIViewTintAdjustmentMode相关(一)
2. 容易忽略的那些小点总结 (二) —— CALayer相关(一)
3. 容易忽略的那些小点总结 (三) —— CALayer相关(二)
contentsGravity
/* A string defining how the contents of the layer is mapped into its
* bounds rect. Options are `center', `top', `bottom', `left',
* `right', `topLeft', `topRight', `bottomLeft', `bottomRight',
* `resize', `resizeAspect', `resizeAspectFill'. The default value is
* `resize'. Note that "bottom" always means "Minimum Y" and "top"
* always means "Maximum Y". */
一个字符串定义了layer的contents是如何映射到它的边界矩形内部的,选项有`center', `top',
`bottom', `left', `right', `topLeft', `topRight', `bottomLeft', `bottomRight',
`resize', `resizeAspect', `resizeAspectFill',默认值是`resize',
注意"bottom"意思是"Minimum Y","top"的意思是"Maximum Y"。
@property(copy) NSString *contentsGravity;
contentsGravity可以去下面的值
/** Layer `contentsGravity' values. **/
CA_EXTERN NSString * const kCAGravityCenter
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityTop
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityBottom
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityLeft
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityRight
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityTopLeft
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityTopRight
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityBottomLeft
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityBottomRight
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityResize
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityResizeAspect
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAGravityResizeAspectFill
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
和cotentMode
一样,contentsGravity
的目的是为了决定内容在图层的边界中怎么对齐,kCAGravityResizeAspect
的效果等同于UIViewContentModeScaleAspectFit
, 同时它还能在图层中等比例拉伸以适应图层的边界。默认值是kCAGravityResize
重要:1) contents gravity常数的命名是基于垂直轴的方向。 如果您使用垂直分量的重力常量,例如 kCAGravityTop,你也应该检查图层的contentsAreFlipped。 如果是YES,则kCAGravityTop将内容对齐到图层的底部,kCAGravityBottom将内容对齐到图层的顶部。2) macOS和iOS中视图的默认坐标系统在纵轴的方向上有所不同:在macOS中,默认坐标系的原点位于绘图区域的左下方,往上是正值,在iOS中默认坐标系统的起点位于绘图区域的左上角,往下是正值。 3) 有关更多信息,请参阅Coordinate system。
图1显示了为图层的contentsGravity
属性设置不同值的效果的四个示例。
- 第一张图是默认的kCAGravityResize
- 第二张图 kCAGravityCenter
- 第三张图 contentsAreFlipped ? kCAGravityTop : kCAGravityBottom
- 第四张图 contentsAreFlipped ? kCAGravityBottomLeft : kCAGravityTopLeft
contentsScale
先看一下这个属性的API文档。
/* Defines the scale factor applied to the contents of the layer. If
* the physical size of the contents is '(w, h)' then the logical size
* (i.e. for contentsGravity calculations) is defined as '(w /
* contentsScale, h / contentsScale)'. Applies to both images provided
* explicitly and content provided via -drawInContext: (i.e. if
* contentsScale is two -drawInContext: will draw into a buffer twice
* as large as the layer bounds). Defaults to one. Animatable. */
定义应用于图层内容的比例因子。 如果内容的物理尺寸是“(w,h)”,那么逻辑尺寸(即用于contentGravity计算)被定义为'(w / contentsScale,h / contentsScale)'。 适用于显式提供的图像和通过-drawInContext提供的内容(即如果contentsScale是2,-drawInContext:将绘制到缓冲区大小为layer bounds的2倍), 默认为1,可动画。
@property CGFloat contentsScale
CA_AVAILABLE_STARTING (10.7, 4.0, 9.0, 2.0);
也可以这么理解
该值定义了图层的逻辑坐标空间(以点为单位)和物理坐标空间(以像素为单位)之间的映射。 较高的比例因子表示在渲染时间层中的每个点由多于一个像素表示。 例如,如果比例因子为2.0,图层边界为50 x 50点,则用于呈现图层内容的位图大小为100 x 100像素。
此属性的默认值是1.0。 对于附加到视图的图层,视图自动将比例因子自动更改为适合当前屏幕的值。 对于您自己创建和管理的图层,您必须根据屏幕的分辨率和您提供的内容自行设置此属性的值。
Core Animation
使用您指定的值作为提示来确定如何呈现您的内容。
还是先看一下这个属性的API文档
/* A rectangle in normalized image coordinates defining the scaled
* center part of the `contents' image.
*
* When an image is resized due to its `contentsGravity' property its
* center part implicitly defines the 3x3 grid that controls how the
* image is scaled to its drawn size. The center part is stretched in
* both dimensions; the top and bottom parts are only stretched
* horizontally; the left and right parts are only stretched
* vertically; the four corner parts are not stretched at all. (This is
* often called "9-slice scaling".)
*
* The rectangle is interpreted after the effects of the `contentsRect'
* property have been applied. It defaults to the unit rectangle [0 0 1
* 1] meaning that the entire image is scaled. As a special case, if
* the width or height is zero, it is implicitly adjusted to the width
* or height of a single source pixel centered at that position. If the
* rectangle extends outside the [0 0 1 1] unit rectangle the result is
* undefined. Animatable. */
标准化图像坐标中的矩形定义“contents”图像的缩放中心部分。 当由于其“contentsGravity”属性而调整图像大小时
中心部分隐含地定义了3x3网格,其控制如何将图像缩放到其绘制的大小。 中间部分在两个方向都被拉伸; 顶部和底部只有水平伸展; 左右部分只是垂直拉伸; 四个角落部分根本不被拉伸。 (这通常被称为“9-slice scaling”)。
在应用“contentsRect”属性的效果之后,该矩形被解释。 它默认为单位矩形[0 0 1 1],意味着整个图像被缩放。 作为特殊情况,如果宽度或高度为零,则隐式地调整为以该位置为中心的单个源像素的宽度或高度。 如果矩形延伸到[0 0 1 1]单位矩形之外,则结果是不确定的,可动画。
@property CGRect contentsCenter;
也可以这么理解
如果图层内容被调整,定义如何调整图层内容的缩放比例的矩形,可动画。
您可以使用此属性将图层的内容细分为3x3网格。此属性中的值指定该网格中的中心矩形的位置和大小。如果图层的
contentsGravity
属性设置为调整大小模式之一,则调整图层大小会导致缩放在网格的每个矩形中以不同的方式出现。中心矩形在两个方向上都被拉伸,顶部中心矩形和底部中心矩形仅被水平拉伸,左中心矩形和右心矩形仅被垂直拉伸,并且四角矩形根本不被拉伸。因此,您可以使用这种技术来实现使用三部分或九部分图像的可拉伸背景或图像。此属性中的值默认设置为单位矩形
(0.0,0.0)(1.0,1.0)
,这将导致整个图像在两个维度上缩放。如果指定一个在单位矩形外延伸的矩形,则结果是未定义的。只有将contentsRect
属性应用于图像后,才能应用指定的矩形。
注意:如果此属性中矩形的宽度或高度非常小或为0,则该值将隐式更改为以指定位置为中心的单个源像素的宽度或高度。
我们先正常的显示一个图片,看一下代码
//创建CGImageRef(test.png是工程Bundle中的资源图片文件)
CGImageRef img = [UIImage imageNamed:@"test.png"].CGImage;
//创建CALayer
CALayer *layer = [CALayer layer];
//设置CALayer的内容
layer.contents = (__bridge id)img;
layer.frame = CGRectMake(20, 20, CGImageGetWidth(img), CGImageGetHeight(img));
//添加Layer到View
[self.view.layer addSublayer:layer];
运行起来图形如下所示
下面我们在设置点东西
//选择右上角的四分之一为内容
layer.contentsRect = CGRectMake(0.5, 0, 0.5, 0.5);
//拉伸
layer.contentsGravity = kCAGravityResize;
这就会产生一个效果,让整个Layer只显示右上角四分之一的内容,而Layer的大小保持不变,所以显示的内容会被拉伸,如下所示。
下面就可以讲CALayer的contentsCenter
属性了,因为contentsCenter
属性只有在图片被拉伸后才会起作用,contentsCenter可以用来定义全面拉伸的范围。什么是“全面拉伸”?看一下下图
如果contentsCenter属性是上图中间的蓝色方框,那么当这个图片被拉伸后,contentsCenter属性定义的区域会被全面拉伸(也就是从四个方向进行放大或者缩小),而被这个方框分割后的其他方格会按照上图所表示的进行横向或者纵向的拉伸,或者某些方框根本不拉伸!这就是contentsCenter属性的意义。
contentsCenter属性和contentsRect属性一样,同样是以比例作单位。两个属性可以叠加,如果contentsRect属性被设置,contentsCenter属性就会操作contentsRect属性所定义的范围。
那么,接着上面的代码,我们想把上图中的左下角的四分之一部分进行全面拉伸,那么加入设置contentsCenter属性的代码:
//左下角的四分之一拉伸
layer.contentsCenter = CGRectMake(0, 0.5, 0.5, 0.5);
contentsFormat
还是先看一下这个属性的API
/* A hint for the desired storage format of the layer contents provided by
* -drawLayerInContext. Defaults to kCAContentsFormatRGBA8Uint. Note that this
* does not affect the interpretation of the `contents' property directly. */
-drawLayerInContext提供的图层内容的所需存储格式的提示。 缺省为kCAContentsFormatRGBA8Uint。
请注意,这不会直接影响“contents”属性的解释。
@property(copy) NSString *contentsFormat
CA_AVAILABLE_STARTING (10.12, 10.0, 10.0, 3.0);
你也可以这么理解
- 这个属性的默认值是
kCAContentsFormatRGBA8Uint
。 - UIView和图层支持的NSView对象可能会将值更改为适合当前设备的格式。
这个值可以有三个选择,如下所示
/** Layer `contentsFormat` values. **/
CA_EXTERN NSString * const kCAContentsFormatRGBA8Uint /* RGBA UInt8 per component */
CA_AVAILABLE_STARTING (10.12, 10.0, 10.0, 3.0);
CA_EXTERN NSString * const kCAContentsFormatRGBA16Float /* RGBA half-float 16-bit per component */
CA_AVAILABLE_STARTING (10.12, 10.0, 10.0, 3.0);
CA_EXTERN NSString * const kCAContentsFormatGray8Uint /* Grayscale with alpha (if not opaque) UInt8 per component */
CA_AVAILABLE_STARTING (10.12, 10.0, 10.0, 3.0);
这个很好理解了,就是色值的组成形式,比如说kCAContentsFormatRGBA8Uint
就表示每一位都是UInt8类型的数据。
minificationFilter和magnificationFilter
有时候,显示一个非真实大小的图片确实是我们需要的效果。比如说一个头像或是图片的缩略图,再比如说一个可以被拖拽和伸缩的大图。这些情况下,为同一图片的不同大小存储不同的图片显得又不切实际。
当图片需要显示不同的大小的时候,有一种叫做拉伸过滤的算法就起到作用了。它作用于原图的像素上并根据需要生成新的像素显示在屏幕上。
还是先看一下这个属性的API
/* The filter types to use when rendering the `contents' property of
* the layer. The minification filter is used when to reduce the size
* of image data, the magnification filter to increase the size of
* image data. Currently the allowed values are `nearest' and `linear'.
* Both properties default to `linear'. */
渲染图层的“contents”属性时使用的过滤器类型。 minification过滤器用于缩小图像数据的大小时,
magnification过滤器增加图像数据的大小。 目前允许的值是`nearest' 和 `linear'的。 这两个
属性默认为`linear'。
@property(copy) NSString *minificationFilter;
@property(copy) NSString *magnificationFilter;
它们可选的值如下所示:
/** Contents filter names. **/
CA_EXTERN NSString * const kCAFilterNearest
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAFilterLinear
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
/* Trilinear minification filter. Enables mipmap generation. Some
* renderers may ignore this, or impose additional restrictions, such
* as source images requiring power-of-two dimensions. */
CA_EXTERN NSString * const kCAFilterTrilinear
CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);
也可以这么理解
-
minificationFilter
属性的可能值在Scaling Filters列出来,默认值是kCAFilterLinear。 -
magnificationFilter
属性的可能值在Scaling Filters列出来,默认值是kCAFilterLinear。图1显示了10 X 10点图像的圆形被放大10倍时,linear
和nearest
滤波之间的差异。
左边的圆圈使用的是kCAFilterLinear,右边使用的是kCAFilterNearest。
kCAFilterLinear
过滤器采用双线性滤波算法,它在大多数情况下都表现良好。双线性滤波算法通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是当放大倍数比较大的时候图片就模糊不清了。kCAFilterTrilinear
和kCAFilterLinear
非常相似,大部分情况下二者都看不出来有什么差别。但是,较双线性滤波算法而言,三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而得到最后的结果。
-
kCAFilterNearest
是一种比较武断的方法。从名字不难看出,这个算法(也叫最近过滤)就是取样最近的单像素点而不管其他的颜色。这样做非常快,也不会使图片模糊。但是,最明显的效果就是,会使得压缩图片更糟,图片放大之后也显得块状或是马赛克严重。
- 总的来说,对于比较小的图或者是差异特别明显,极少斜线的大图,最近过滤算法会保留这种差异明显的特质以呈现更好的结果。但是对于大多数的图尤其是有很多斜线或是曲线轮廓的图片来说,最近过滤算法会导致更差的结果。换句话说,线性过滤保留了形状,最近过滤则保留了像素的差异。
下面我们看一个别人提供的例子。
参考文章
1. iOS: 关于CALayer的contentsCenter属性
2. iOS: 使用CALayer的layoutSublayers方法来规划子Layer
3. iOS: CALayer的timeOffset在speed设置成0后不起作用
4. iOS: 视觉化CALayer的zPosition
5. iOS: CATextLayer的sizeToFit方法
6. 4.5 拉伸过滤
后记
本篇已结束,后面更精彩,欢迎关注~~~