圖層幾何學
- 內(nèi)部是如何根據(jù)父圖層和兄弟圖層來控制位置和尺寸的,如何管理圖層的幾何結構,如何被自動調(diào)整和自動布局影響的。
布局
- <mark>
UIView
有三個比較重要的布局屬性:frame,bounds 和 center
,CALayer
對應地叫做frame,bounds 和 position。
</mark>frame
代表了圖層的外部坐標bounds
是內(nèi)部坐標center
和position
都代表了相對于父圖層anchorPoint
所在的位置。- 當操縱視圖的
frame
,實際上是在改變位于視圖下方CALayer
的frame
,不能夠獨立于圖層之外改變視圖的frame
。frame
并不是一個非常清晰的屬性,它其實是一個虛擬屬性,是根據(jù)bounds,position和transform
計算而來,所以當其中任何一個值發(fā)生改變,frame
都會變化。相反,改變frame
的值同樣會影響到他們當中的值
- 如圖:當對圖層做變換的時候,比如旋轉或者縮放,
frame
實際上代表了覆蓋在圖層旋轉之后的整個軸對齊的矩形區(qū)域,也就是說frame
的寬高可能和bounds
的寬高不再一致
錨點
anchorPoint
用單位坐標來描述,默認坐標是{0.5, 0.5}
。- 個人理解:如下圖,中心點左右兩邊邊距皆為視圖寬度的一半,高度同理。改變視圖中心點的位置至左上角后,同樣有此規(guī)則,所以看到的視圖向右下角移動了。
坐標系
一個圖層的
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
,假設原坐標系的起始點在左上角,現(xiàn)改成左下角,坐標系隨之改變。Z坐標軸
CALayer
存在于一個三維空間當中,還有另外兩個屬性:
zPosition
:最實用的功能就是改變圖層的顯示順序(圖層是根據(jù)它們子圖層的sublayers
出現(xiàn)的順序來類繪制的),不能改變事件傳遞的順序。
anchorPointZ
:改變錨點在Z
軸的位置。點擊測試
CALayer
不直接處理觸摸,手勢事件,但有方法幫你處理事件。
-containsPoint:
:接受一個在本圖層坐標系下的點,如果這個點在圖層frame
范圍內(nèi)就返回YES
。
[self.layerView.layer containsPoint:point]
-hitTest:
:接受一個在本圖層坐標系下的點,如果這個點在圖層frame
范圍內(nèi)就返回圖層本身,在之外則返回nil
。測算的順序嚴格依賴于圖層樹當中的圖層順序。
[self.layerView.layer hitTest:point]
如果改變了圖層的 Z 軸順序,將不能檢測到最前方的視圖點擊事件,因為被另一個視圖遮蓋住了,雖然
zPosition
值較小,但是在圖層樹中的順序靠前。自動布局
CALayer
的布局- 通過
CALayerDelegate
的layoutDublayersOfLayer:
函數(shù)。當圖層的bounds
發(fā)生改變或者圖層的setNeedsLayout
方法被調(diào)用的時候,該方法就會被執(zhí)行。- 不能像
UIView
一樣做到屏幕自適應,也是為什么使用視圖而不是圖層構建程序的原因之一。
視覺效果
圓角
conrnerRadius
:圓角的曲率,只影響背景顏色而不影響背景圖片或是子圖層。可以通過把masksToBounds
設置成YES
,圖層里面的所有東西都會被截取。- 創(chuàng)建一個有圓角和直角的圖形可以通過圖層蒙板或者
CAShapeLayer
。圖層邊框
borderWidth
borderColor
:CGColorRef
類型- 邊框是跟隨圖層的邊界變化的,而不是圖層里面的內(nèi)容
陰影
shadowOpacity
:0(不可見) ~ 1(完全不透明)shadowColor
: 陰影的顏色shadowOffset
: 陰影的方向和距離,默認 {0, -3},寬度決定橫向位移,高度決定縱向位移。(前身是 Mac OS,兩者 Y 軸顛倒,Mac OS 陰影朝下,iOS就朝上了)shadowRadius
: 陰影模糊度陰影裁剪
- 圖層的陰影繼承自內(nèi)容的外形,而不是根據(jù)邊界和角半徑來確定。
masksToBounds
把陰影裁剪的解決辦法:- 兩個圖層:一個只畫陰影的空的外圖層,一個用
masksToBounds
裁剪內(nèi)容的內(nèi)圖層。
shadowPath
屬性
- 計算陰影是個消耗性能的操作,通過該屬性來告訴系統(tǒng)陰影的形狀,提高性能。
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像素顯示在屏幕上
- 能夠顯示最好的畫質(zhì),像素既沒有被壓縮也沒有被拉伸。
- 能更好的使用內(nèi)存,因為這就是所有你要存儲的東西。
- 最好的性能表現(xiàn),CPU不需要為此額外的計算。
minificationFilter
:縮小圖片,magnificationFilter
:放大圖片kCAFilterLinear
:默認值,采用雙線性濾波算法,通過對多個像素取樣最終生成新的值,得到一個平滑的表現(xiàn)不錯的拉伸。但是當放大倍數(shù)比較大的時候圖片就模糊不清。kCAFilterTrilinear
:和kCAFilterLinear
非常相似,采用三線性濾波算法存儲了多個大小情況下的圖片(也叫多重貼圖),并三維取樣,同時結合大圖和小圖的存儲進而?得到最后的結果。<mark>好處:在于算法能夠從一系列已經(jīng)接近于最終大小的圖片中得到想要的結果,也就是說不要對很多像素同步取樣。這不僅提高了性能,也避免了小概率因舍入錯誤引起的取樣失靈的問題</mark>kCAFilterNearest
:采用最近過濾算法,取樣最近的單像素點而不管其他的顏色。速度快不會產(chǎn)生模糊,但會降低質(zhì)量并像素化圖像,馬賽克化。適用于比較小的圖或者是差異特別明顯,極少斜線的大圖。組透明
- 如果你給一個圖層設置了
opacity
屬性,那它的子圖層都會受此影響。- 當你顯示一個
50%
透明度的圖層時,圖層的每個像素都會一半顯示自己的顏色,另一半顯示圖層下面的顏色。這是正常的透明度的表現(xiàn)。- 但是如果圖層包含一個同樣顯示
50%
透明的子圖層時,你所看到的視圖,50%
來自子視圖,25%
來了圖層本身的顏色,另外的25%
則來自背景色。- 個人理解:當只有一個圖層時,
50%
是自己的顏色,50%
是背景的;當一個圖層有一個子圖層時,50%
自己,另外50%
的一半給父圖層,一半給背景顏色。
- 整體透明解決方案:
- 設置
Info.plist
文件中的UIViewGroupOpacity
為YES
來達到這個效果,但會影響到這個應用其他部分。CALayer
的shouldRasterize
屬性為YES
,在應用透明度之前,圖層及其子圖層都會被整合成一個整體的圖片,這樣就沒有透明度混合的問題了當
shouldRasterize
和UIViewGroupOpacity
一起的時候,性能問題就出現(xiàn)了)