如圖:
UIView
可以處理觸摸事件议街,但CALayer
是不支持交互的(不清楚具體的相應(yīng)鏈的)秃踩。實(shí)際上這些背后關(guān)聯(lián)的圖層才是真正用來在屏幕上顯示和做動畫嘁扼,UIView
僅僅是對它的一個(gè)封裝拷肌,提供了一些iOS類似于處理觸摸的具體功能糟秘,以及Core Animation底層方法的高級接口简逮。
<四個(gè)層級關(guān)系>:視圖層級、圖層樹尿赚、呈現(xiàn)樹和渲染樹散庶。
屬性介紹
-
Contents:
事實(shí)上,你真正要賦值的類型應(yīng)該是CGImageRef凌净,它是一個(gè)指向CGImage結(jié)構(gòu)的指針悲龟。UIImage有一個(gè)CGImage屬性,它返回一個(gè)"CGImageRef",如果你想把這個(gè)值直接賦值給CALayer的
contents
冰寻,那你將會得到一個(gè)編譯錯誤须教。因?yàn)镃GImageRef并不是一個(gè)真正的Cocoa對象,而是一個(gè)Core Foundation類型性雄∶恍叮可以通過bridged關(guān)鍵字轉(zhuǎn)換。
@property(nullable, strong) id contents;
-
contentMode:
//對應(yīng)UIView的contentMode.
@property(copy) NSString *contentsGravity;
-
geometryFlipped:
//決定了一個(gè)圖層的坐標(biāo)是否相對于父圖層垂直翻轉(zhuǎn)秒旋。是為了適配iOS和OS X兩種不同坐標(biāo)系的情況约计。
@property(getter=isGeometryFlipped) BOOL geometryFlipped;
-
zPosition:
//常用于做CATransform3D變換及更改圖層的顯示順序。<不能改變事件傳遞的順序>
@property CGFloat zPosition;
-
anchorPointZ:
//在Z軸上描述圖層位置的浮點(diǎn)類型
@property CGFloat anchorPointZ;
-
position:
指定了anchorPoint相對于父圖層的位置迁筛。
//對應(yīng)UIView的center.
@property CGPoint position;
-
anchorPoint:
錨點(diǎn)煤蚌,可以理解為固定圖層的點(diǎn)。相對于自身坐標(biāo)系细卧,取值范圍0~1尉桩,默認(rèn)(0.5,0.5)贪庙。
@property CGPoint anchorPoint;
position和anchorPoint的換算公式:徹底理解position和anchorPoint
position.x = frame.origin.x + anchorPoint.x * bounds.size.width蜘犁;
position.y = frame.origin.y + anchorPoint.y * bounds.size.height;
-
contentsScale:
屬性定義了寄宿圖的像素尺寸和視圖大小的比例止邮,默認(rèn)情況下它是一個(gè)值為1.0的浮點(diǎn)數(shù)这橙。當(dāng)設(shè)置了
contentsGravity
屬性會有所影響奏窑。
//如果contentsScale設(shè)置為1.0,將會以每個(gè)點(diǎn)1個(gè)像素繪制圖片屈扎。并且把contentsGravity設(shè)置為kCAGravityCenter(這個(gè)值并不會拉伸圖片)埃唯,那將會有很明顯的變化。
@property CGFloat contentsScale
-
contentsRect:
屬性允許我們在圖層邊框里顯示寄宿圖的一個(gè)子域鹰晨,
contentsRect
不是按點(diǎn)來計(jì)算的墨叛,它使用了單位坐標(biāo),單位坐標(biāo)指定在0到1之間模蜡,是一個(gè)相對值(像素和點(diǎn)就是絕對值)
@property CGRect contentsRect;
-
contentsCenter:《contentsCenter 介紹》
其實(shí)是一個(gè)CGRect漠趁,它定義了一個(gè)固定的邊框和一個(gè)在圖層上可拉伸的區(qū)域。
//單位坐標(biāo)哩牍,定義的區(qū)域會被全面拉伸(也就是從四個(gè)方向進(jìn)行放大或者縮小)棚潦,所'侵占'的地方的視圖也會進(jìn)行相應(yīng)的拉伸變換。
@property CGRect contentsCenter;
-
masksToBounds:
//等同于UIView的clipsToBounds.
@property BOOL masksToBounds;
-
mask:
是個(gè)CALayer類型膝昆,有和其他圖層一樣的繪制和布局屬性。它類似于一個(gè)子圖層叠必,相對于父圖層(即擁有該屬性的圖層)布局荚孵,但是它卻不是一個(gè)普通的子圖層。不同于那些繪制在父圖層中的子圖層纬朝,
mask
圖層定義了父圖層的部分可見區(qū)域收叶。
@property(nullable, strong) CALayer *mask;
-
minificationFilter && magnificationFilter
@property(copy) NSString *minificationFilter;//縮小:
@property(copy) NSString *magnificationFilter;//放大:
--值的介紹:
1共苛。kCAFilterLinear
:默認(rèn)值判没,采用雙線性濾波算法,它在大多數(shù)情況下都表現(xiàn)良好隅茎。雙線性濾波算法通過對多個(gè)像素取樣最終生成新的值澄峰,得到一個(gè)平滑的表現(xiàn)不錯的拉伸。但是當(dāng)放大倍數(shù)比較大的時(shí)候圖片就模糊不清了辟犀。
2俏竞。kCAFilterTrilinear
:三線性濾波算法存儲了多個(gè)大小情況下的圖片(也叫多重貼圖),并三維取樣堂竟,同時(shí)結(jié)合大圖和小圖的存儲進(jìn)而得到最后的結(jié)果魂毁。這不僅提高了性能,也避免了小概率因舍入錯誤引起的取樣失靈的問題.
3出嘹。kCAFilterNearest
:取樣最近的單像素點(diǎn)而不管其他的顏色席楚。這樣做非常快税稼,也不會使圖片模糊烦秩。但是垮斯,最明顯的效果就是,會使得壓縮圖片更糟闻镶,圖片放大之后也顯得塊狀或是馬賽克嚴(yán)重甚脉。(不推薦)。
--總結(jié):
對于比較小的圖或者是差異特別明顯铆农,極少斜線的大圖牺氨,最近過濾算法會保留這種差異明顯的特質(zhì)以呈現(xiàn)更好的結(jié)果。但是對于大多數(shù)的圖尤其是有很多斜線或是曲線輪廓的圖片來說墩剖,最近過濾算法會導(dǎo)致更差的結(jié)果猴凹。換句話說,線性過濾保留了形狀岭皂,最近過濾則保留了像素的差異郊霎。
-
shouldRasterize:
為了啟用
shouldRasterize
屬性,我們設(shè)置了圖層的rasterizationScale
屬性爷绘。默認(rèn)情況下书劝,所有圖層拉伸都是1.0, 所以如果你使用了shouldRasterize
屬性土至,你就要確保你設(shè)置了rasterizationScale
屬性去匹配屏幕购对,以防止出現(xiàn)Retina屏幕像素化的問題。(info.plist文件中有個(gè)全局設(shè)置屬性:UIViewGroupOpacity)
//組透明效果
@property BOOL shouldRasterize;
-
affineTransform
這里只提供了set和get方法陶因。
- (CGAffineTransform)affineTransform;
- (void)setAffineTransform:(CGAffineTransform)m;
—栗子:
CGAffineTransform affine = CGAffineTransformMakeRotation(M_PI_4);
blueLayer.affineTransform = affine;
代理
CALayer有一個(gè)可選的
delegate
屬性骡苞,實(shí)現(xiàn)了CALayerDelegate
協(xié)議,當(dāng)CALayer需要一個(gè)內(nèi)容特定的信息時(shí)楷扬,就會從協(xié)議中請求解幽。CALayerDelegate是一個(gè)非正式協(xié)議,其實(shí)就是說沒有CALayerDelegate @protocol可以讓你在類里面引用啦烘苹。你只需要調(diào)用你想調(diào)用的方法躲株,CALayer會幫你做剩下的。(delegate
屬性被聲明為id類型螟加,所有的代理方法都是可選的)徘溢。
- 當(dāng)需要被重繪時(shí),CALayer會請求它的代理給他一個(gè)寄宿圖來顯示捆探。它通過調(diào)用下面這個(gè)方法做到的:
- (void)displayLayer:(CALayerCALayer *)layer;
- 如果代理不實(shí)現(xiàn)
-displayLayer:
方法然爆,CALayer就會轉(zhuǎn)而嘗試調(diào)用下面這個(gè)方法,在調(diào)用這個(gè)方法之前黍图,CALayer創(chuàng)建了一個(gè)合適尺寸的空寄宿圖(尺寸由bounds
和contentsScale
決定)和一個(gè)Core Graphics的繪制上下文環(huán)境曾雕,為繪制寄宿圖做準(zhǔn)備,他作為ctx參數(shù)傳入助被。
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
—栗子:
CALayer * delegateLayer = [CALayer layer];
[self.view.layer addSublayer:delegateLayer];
delegateLayer.frame = CGRectMake(50, 100, 300, 400);
delegateLayer.backgroundColor = [UIColor brownColor].CGColor;
delegateLayer.delegate = self;//這里需遵循CALayerDelegate協(xié)議剖张。
[delegateLayer display];//這里需要顯式地調(diào)用了-display切诀。不同于UIView,當(dāng)圖層顯示在屏幕上時(shí)搔弄,CALayer不會自動重繪它的內(nèi)容幅虑。它把重繪的決定權(quán)交給了開發(fā)者。
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
//draw a thick red circle
CGContextSetLineWidth(ctx, 10.0f);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
—效果:
—注意:
盡管我們沒有用masksToBounds
屬性顾犹,繪制的那個(gè)圓仍然沿邊界被裁剪了倒庵。這是因?yàn)楫?dāng)你使用CALayerDelegate繪制寄宿圖的時(shí)候,并沒有對超出邊界外的內(nèi)容提供繪制支持炫刷。
當(dāng)UIView創(chuàng)建了它的宿主圖層時(shí)擎宝,它就會自動地把圖層的delegate設(shè)置為它自己,并提供了一個(gè)-displayLayer:
的實(shí)現(xiàn)浑玛,那所有的問題就都沒了绍申。
當(dāng)使用寄宿了視圖的圖層的時(shí)候,你也不必實(shí)現(xiàn)-displayLayer:
和-drawLayer:inContext:
方法來繪制你的寄宿圖顾彰。通常做法是實(shí)現(xiàn)UIView的-drawRect:
方法极阅,UIView就會幫你做完剩下的工作,包括在需要重繪的時(shí)候調(diào)用-display
方法涨享。
其它方法
- UIView會在初始化的時(shí)候調(diào)用+layerClass方法涂屁,然后用它的返回類型來創(chuàng)建宿主圖層。(特別適用灰伟,返回的值代表self.layer)
+(Class)layerClass
- 以下方法可以把定義在一個(gè)圖層坐標(biāo)系下的點(diǎn)或者矩形轉(zhuǎn)換成另一個(gè)圖層坐標(biāo)系下的點(diǎn)或者矩形.
- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;//得到layer上的point的點(diǎn)相對于方法調(diào)用者的相對point。
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
- 接受一個(gè)在本圖層坐標(biāo)系下的
CGPoint
儒旬,如果這個(gè)點(diǎn)在圖層frame
范圍內(nèi)就返回YES
栏账。需要把觸摸坐標(biāo)轉(zhuǎn)換成每個(gè)圖層坐標(biāo)系下的坐標(biāo),結(jié)果很不方便栈源。
- (BOOL)containsPoint:(CGPoint)p;
- 方法同樣接受一個(gè)
CGPoint
類型參數(shù)挡爵,而不是BOOL
類型,它返回圖層本身甚垦,或者包含這個(gè)坐標(biāo)點(diǎn)的葉子節(jié)點(diǎn)圖層茶鹃。這意味著不再需要像使用-containsPoint:
那樣,人工地在每個(gè)子圖層變換或者測試點(diǎn)擊的坐標(biāo)艰亮。如果這個(gè)點(diǎn)在最外面圖層的范圍之外闭翩,則返回nil。
- (nullable CALayer *)hitTest:(CGPoint)p;
—栗子:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [[touches anyObject] locationInView:self.view];
CALayer *layer = [self.layerView.layer hitTest:point];
if (layer == self.blueLayer) {
} else if (layer == self.layerView.layer) {
}
}