图层几何学
- 内部是如何根据父图层和兄弟图层来控制位置和尺寸的,如何管理图层的几何结构,如何被自动调整和自动布局影响的。
布局
- <mark>
UIView
有三个比较重要的布局属性:frame,bounds 和 center
,CALayer
对应地叫做frame,bounds 和 position。
</mark>frame
代表了图层的外部坐标bounds
是内部坐标center
和position
都代表了相对于父图层anchorPoint
所在的位置。- 当操纵视图的
frame
,实际上是在改变位于视图下方CALayer
的frame
,不能够独立于图层之外改变视图的frame
。frame
并不是一个非常清晰的属性,它其实是一个虚拟属性,是根据bounds,position和transform
计算而来,所以当其中任何一个值发生改变,frame
都会变化。相反,改变frame
的值同样会影响到他们当中的值
- 如图:当对图层做变换的时候,比如旋转或者缩放,
frame
实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,也就是说frame
的宽高可能和bounds
的宽高不再一致
锚点
anchorPoint
用单位坐标来描述,默认坐标是{0.5, 0.5}
。- 个人理解:如下图,中心点左右两边边距皆为视图宽度的一半,高度同理。改变视图中心点的位置至左上角后,同样有此规则,所以看到的视图向右下角移动了。
坐标系
一个图层的
position
依赖于它父图层的bounds
CALayer
提供了一些方法(把定义在一个图层坐标系下的点或者矩形转换成另一个图层坐标系下的点或者矩形):
- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
翻转的几何结构:
iOS
:图层的position
位于父图层的左上角
Mac OS
:位于左下角。
geometryFlipped
:决定了一个图层的坐标是否相对于父图层垂直翻转,是一个BOOL
类型。(它的所有子图层也同理,除非把它们的geometryFlipped
属性也设为YES
)。个人理解:设置为
YES
,假设原坐标系的起始点在左上角,现改成左下角,坐标系随之改变。Z坐标轴
CALayer
存在于一个三维空间当中,还有另外两个属性:
zPosition
:最实用的功能就是改变图层的显示顺序(图层是根据它们子图层的sublayers
出现的顺序来类绘制的),不能改变事件传递的顺序。
anchorPointZ
:改变锚点在Z
轴的位置。点击测试
CALayer
不直接处理触摸,手势事件,但有方法帮你处理事件。
-containsPoint:
:接受一个在本图层坐标系下的点,如果这个点在图层frame
范围内就返回YES
。
[self.layerView.layer containsPoint:point]
-hitTest:
:接受一个在本图层坐标系下的点,如果这个点在图层frame
范围内就返回图层本身,在之外则返回nil
。测算的顺序严格依赖于图层树当中的图层顺序。
[self.layerView.layer hitTest:point]
如果改变了图层的 Z 轴顺序,将不能检测到最前方的视图点击事件,因为被另一个视图遮盖住了,虽然
zPosition
值较小,但是在图层树中的顺序靠前。自动布局
CALayer
的布局- 通过
CALayerDelegate
的layoutDublayersOfLayer:
函数。当图层的bounds
发生改变或者图层的setNeedsLayout
方法被调用的时候,该方法就会被执行。- 不能像
UIView
一样做到屏幕自适应,也是为什么使用视图而不是图层构建程序的原因之一。
视觉效果
圆角
conrnerRadius
:圆角的曲率,只影响背景颜色而不影响背景图片或是子图层。可以通过把masksToBounds
设置成YES
,图层里面的所有东西都会被截取。- 创建一个有圆角和直角的图形可以通过图层蒙板或者
CAShapeLayer
。图层边框
borderWidth
borderColor
:CGColorRef
类型- 边框是跟随图层的边界变化的,而不是图层里面的内容
阴影
shadowOpacity
:0(不可见) ~ 1(完全不透明)shadowColor
: 阴影的颜色shadowOffset
: 阴影的方向和距离,默认 {0, -3},宽度决定横向位移,高度决定纵向位移。(前身是 Mac OS,两者 Y 轴颠倒,Mac OS 阴影朝下,iOS就朝上了)shadowRadius
: 阴影模糊度阴影裁剪
- 图层的阴影继承自内容的外形,而不是根据边界和角半径来确定。
masksToBounds
把阴影裁剪的解决办法:- 两个图层:一个只画阴影的空的外图层,一个用
masksToBounds
裁剪内容的内图层。
shadowPath
属性
- 计算阴影是个消耗性能的操作,通过该属性来告诉系统阴影的形状,提高性能。
CGPathRef
类型,一个指向CGPath
的指针,CGPath
是一个Core Graphics
对象,用来指定任意的一个矢量图形。- 该属性用来指定任意阴影形状
图层蒙版
mask
属性:图层实心部分会被保留下来,其他地方会被抛弃。
@interface ViewCOntroller @property (nonatomic, weak) IBOutlet UIImageView *imageView @end @implementation ViewController - (void)viewDidLoad{ [super viewDidLoad]; CALayer *maskLayer = [CALayer layer]; maskLayer.frame = self.layerView.bounds; UIImage *maskImage = [UIImage imageNamed:@"Cone.png"]; maskLayer.contents = (__bridge id)maskImage.CGImage; self.imageView.layer.mask = maskLayer; } @end
拉伸过滤
- 以正确的比例和正确的1:1像素显示在屏幕上
- 能够显示最好的画质,像素既没有被压缩也没有被拉伸。
- 能更好的使用内存,因为这就是所有你要存储的东西。
- 最好的性能表现,CPU不需要为此额外的计算。
minificationFilter
:缩小图片,magnificationFilter
:放大图片kCAFilterLinear
:默认值,采用双线性滤波算法,通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是当放大倍数比较大的时候图片就模糊不清。kCAFilterTrilinear
:和kCAFilterLinear
非常相似,采用三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而�得到最后的结果。<mark>好处:在于算法能够从一系列已经接近于最终大小的图片中得到想要的结果,也就是说不要对很多像素同步取样。这不仅提高了性能,也避免了小概率因舍入错误引起的取样失灵的问题</mark>kCAFilterNearest
:采用最近过滤算法,取样最近的单像素点而不管其他的颜色。速度快不会产生模糊,但会降低质量并像素化图像,马赛克化。适用于比较小的图或者是差异特别明显,极少斜线的大图。组透明
- 如果你给一个图层设置了
opacity
属性,那它的子图层都会受此影响。- 当你显示一个
50%
透明度的图层时,图层的每个像素都会一半显示自己的颜色,另一半显示图层下面的颜色。这是正常的透明度的表现。- 但是如果图层包含一个同样显示
50%
透明的子图层时,你所看到的视图,50%
来自子视图,25%
来了图层本身的颜色,另外的25%
则来自背景色。- 个人理解:当只有一个图层时,
50%
是自己的颜色,50%
是背景的;当一个图层有一个子图层时,50%
自己,另外50%
的一半给父图层,一半给背景颜色。
- 整体透明解决方案:
- 设置
Info.plist
文件中的UIViewGroupOpacity
为YES
来达到这个效果,但会影响到这个应用其他部分。CALayer
的shouldRasterize
属性为YES
,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,这样就没有透明度混合的问题了当
shouldRasterize
和UIViewGroupOpacity
一起的时候,性能问题就出现了)