上一篇《iOS CALayer图层漫谈(二)》我们聊了CALayer几何学的一些知识,这一篇呢我们来聊一下CALayer的一些视觉效果。
CALayer的圆角、边框、阴影
其实说到圆角我相信大家平时都已经用的很多了,我们通过cornerRadius
这个属性来控制图层角的曲率。
layer.cornerRadius = 5.f;
其实这个曲率值只会影响背景颜色,而不会影响到背景图片或子图层。所以此时超出圆角部分的子图层或内容依然会显示,只有我们将maskToBounds
设置成YES
的时候,超出图层圆角范围的子图层或内容才会被截取。
同样,边框也是我们平常用的比较多的效果,这里就不详细解释了直接上代码吧
layer.borderWidth = 2.f;
layer.borderColor = [UIColor redColor].CGColor; // 接收一个CGColorRef类型的值
这里要强调一下的是:边框并不会将子图层(或者是寄宿图)的形状计算进来,如果有子图层(或者是寄宿图)超出了边界,边框依然会沿着图层的边界绘制出来,这跟下面要介绍的阴影正好相反。
阴影种效果也可以说是iOS一个很常见的效果了,由于之前写过一篇关于阴影设置的文章,这里就直接请大家移步到《iOS阴影设置详解》,来了解阴影相关知识。
CALayer的图层蒙版
其实说到图层蒙版,我更想把它叫做自定义形状裁切,但本质上它又的确不是裁切,而是将我们不关心的部分遮盖住了,所以我们叫它图层蒙版。但实际展示出的效果就像裁切那样。前面我们提到了可以通过masksToBounds
进行边界裁切,通过cornerRadius
来设置圆角,但这些形状都很规则,当我们想得到一些边界突兀的图层部分时,我们又该怎么办呢?我们接下来要聊的mask
属性就可以实现。
mask
属性本身就是一个CALayer类型,有和其他图层一样的绘制和布局属性,mask图层的颜色其实是无关紧要的,真正重要的是mask图层的轮廓,当设置了mask图层后,之后mask图层轮廓内的部分会被保留下来。
先来看一下代码(只是产生最后效果部分的代码):
CALayer * shapLayer = [CALayer layer];
shapLayer.frame = CGRectMake(0, 0, 100, 100);
shapLayer.contents = (__bridge id)[UIImage imageNamed:@"1.png"].CGImage;
shapLayer.contentsGravity = kCAGravityResizeAspect;
CALayer * resultLayer = [CALayer layer];
resultLayer.frame = CGRectMake(100, 230, 100, 100);
resultLayer.contents = (__bridge id)[UIImage imageNamed:@"logo.jpeg"].CGImage;
resultLayer.contentsGravity = kCAGravityResizeAspect;
resultLayer.mask = shapLayer;
[self.view.layer addSublayer:resultLayer];
我们看到我们把葡萄形状的图层作为mask图层赋值给了我们想要‘剪裁’的图层,而得到的效果就是上图中的样子。
CALayer的拉伸过滤
我们知道一张图的显示是由固定个数像素点构成的,理想情况下屏幕上的一个点对应图的一个点,这样很完美。但是当我们拉伸或者缩放图片的时候,这种显示规则就变了,呈现出的效果可能和我们想象的也不太一样。比如说我们将一张图放大到一定程度的时候,我们看到的是一个一个方形的像素,就跟马赛克似的,虽然它原本就长这个样子,但有没有办法让图放大后看起来不那么马赛克呢?这就是接下来要聊的两个高大上的属性minificationfilter
和magnificationFilter
了。
这两个属性都对应了三个值:
kCAFilterLinear
kCAFilterNeatest
kCAFilterTrilinear
默认的值都是kCAFilterLinear
,我们把上面这三个值叫做三种过滤器,而每种过滤器都对应一种算法,而其实每种算法都是为了更好的呈现图片拉伸压缩后的展示效果。
由于这三种过滤器的算法都比较底层,所以这里只给大家简单的介绍一下,至于实际应用中选择哪种过滤器,大家可以通过实际的应用场景拉伸所呈现出的效果来决定。
kCAFilterLinear过滤器:采用的是双线性滤波算法,算法通过对多个像素取样最终生成新的值,从而得到一个平滑的表现不错的拉伸。
kCAFilterTrilinear过滤器:和kCAFilterLinear
很相似,相对于kCAFilterLinear
的双线性滤波算法,三线性滤波算法储存了多个大小情况下的图片(也叫多重图),并进行三维取样,同时结合大图小图的存储进而得到最后的结果。
kCAFilterNeatest过滤器:是一种采用比较武断算法的过滤器,从名字上来看就是就近取样,只取最近的单像素点而不管其他颜色。这样做非常快,但最明显的效果就是会使压缩的图片效果更糟,图片放大之后也显得块状,或者是马赛克严重。总的来说对于比较小的图或者是差异特别明显,有很少斜线的大图会呈现出更好的效果。
CALayer的组透明
我们知道UIView中有一个属性叫做alpha
,是用来控制视图透明度的,CALayer也有一个同样的属性叫做opacity
。这两个属性都会影响子层级,也就是说如果你给一个图层设置了透明度,那么它的子图层也会受到影响,并且会产生混合叠加效果。
其实这里涉及一个透明度混合叠加的逻辑:是将所有图层先压缩成一个整体再进行透明度调整呢?还是先进行各自的透明度调整再叠加混合呢?
答案是后者。我们这里有一个实验模型,一个白色背景的UIButton
上内嵌了一个同样白色背景的UILabel
。
如果是第一种逻辑,其实就是将UIButton
和UILable
合并后,作为一个整体进行透明度的调整,展示出的效果应该是“效果一”的样子,其实这也是我们大多数人想要的效果。
但实际情况则是“效果二”的样子,中间部分的透明度明显跟四周的透明度不同,这也是因为透明度混合叠加造成的。
接下来我们通过下面这张图进一步来理解一下透明度叠加的概念:
其实每一个图层的透明度都是由图层树中,当前图层以及它的父图层、祖父图层......一直到根图层的透明度累乘得到的,就像
layer1-1-1
的透明度是50% * 50% * 50% = 12.5%
,但这并不是它最终在屏幕上呈现出的透明度,在layer1-1-1
所在的区域最终在屏幕上呈现出来的透明度是由layer1
、layer1-1
、layer1-1-1
叠加得到的,也就是50% + 25% + 12.5% = 87.5%
。
那由于透明度叠加而导致不是我们想要的效果,我们该怎么办呢?
第一种方法:我们可以修改info.plist
文件中的UIViewGroupOpacity
为YES
来达到效果,但这个设置不好的是它会影响整个应用,整个app都可能会受到不良影响。
另一种方法:我们可以设置CALayer中一个叫做shouldRasterize
的属性,将它设置为YES
后,图层的混合叠加逻辑就变成我们前面提到的第一种逻辑了,首先是将当前图层和它的所有子图层融合,再对当前图层进行整体的透明度调整,这样就会呈现出一个统一的透明度,也就是上面“效果一”展示的效果。
下一篇《iOS CALayer图层漫谈(四)》我们将聊一聊CALayer的空间变换。
版权声明:出自MajorLMJ技术博客的原创作品 ,转载时必须注明出处及相应链接!