图层几何学 -- iOS Core Animation 系列二
《圖層樹和寄宿圖 -- iOS Core Animation 系列一》介紹了圖層的基礎(chǔ)知識(shí)和一些屬性方法。這篇主要內(nèi)容是學(xué)習(xí)下圖層在父圖層上怎么控制位置和尺寸的。
1.布局
首先看一張例圖:
對(duì)于圖上的frame、bounds、center、postion的概念我就不贅述了。如果有不明白的自行搜索下了解一下。
frame代表了圖層的外部坐標(biāo)(也就是在父圖層上占據(jù)的空間),bounds是內(nèi)部坐標(biāo)({0, 0}通常是圖層的左上角),center和position都代表了相對(duì)于父圖層anchorPoint所在的位置視圖的frame、bounds、center屬性僅僅是存取方法,當(dāng)操縱視圖的frame時(shí),實(shí)際上是在改變視圖對(duì)應(yīng)的CALayer的frame, 不能獨(dú)立于圖層之外改變視圖的frame.
如果對(duì)圖層做了變換,比如旋轉(zhuǎn)縮放等。frame的值實(shí)際指的是圖層旋轉(zhuǎn)之后整個(gè)軸對(duì)齊的矩形區(qū)域。此時(shí)frame的寬高可能和bounds的寬高不一致:
2.錨點(diǎn)
默認(rèn)來說,anchorPoint位于圖層的中點(diǎn)。這個(gè)屬性沒有被UIView直接暴露出來。但是圖層的anchorPoint可以被移動(dòng)。我們可以把a(bǔ)nchorPoint置于圖層frame的左上角。將會(huì)出現(xiàn)下圖右側(cè)的情況:
注意上圖,改變anchorPoint后position的值并沒變。
和系列一中提到的contentsRect類似,anchorPoint用單位坐標(biāo)來表示(默認(rèn)情況是{0.5, 0.5})。可以通過指定x和y值小于0或者大于1,使它放置在圖層范圍之外。
2.1 示例
為了學(xué)習(xí)這個(gè)anchorPoint屬性,下面創(chuàng)建一個(gè)鬧鐘的示例demo。
資源文件我是從原文上截圖下來的
創(chuàng)建4個(gè)UIImageView并設(shè)置好約束(都是居中顯示)。
我們用NSTimer來更新鬧鐘,使用視圖的transform屬性來旋轉(zhuǎn)鐘表。
代碼如下:
運(yùn)行項(xiàng)目如下圖:
除了指針圖片的位置,其他的都正常。
可能這時(shí)候我們最先想到的方法,是調(diào)整對(duì)應(yīng)圖片的位置來解決。但是這樣的話,你可以試試,并不能解決問題。不用賣關(guān)子了。這時(shí)候就是要用到anchorPoint的時(shí)候。處理代碼如下:
運(yùn)行完美。
3. 坐標(biāo)系
眾所周知,一個(gè)圖層的position依賴于父圖層的bounds,如果父圖層移動(dòng),所有子圖層也會(huì)跟著移動(dòng)。
CALayer也給我們提供了一些獲取一個(gè)圖層的絕對(duì)位置的方法,或者相對(duì)于另一圖層的位置(而不是它當(dāng)前父圖層的位置):
3.1 z坐標(biāo)軸
和UIView的二維坐標(biāo)不同,CALayer存在于一個(gè)三維空間中,它還提供了zPostion和anchorPointz屬性。
zPosition屬性大多數(shù)不常用,除了三維動(dòng)畫之外,它最實(shí)用的功能是可以改變圖層的顯示順序。
3.2 zPosition演示代碼
我們演示下改變zPosition會(huì)怎么改變視圖的顯示順序。
首先我在SB中設(shè)置兩個(gè)視圖,如下圖:
如果我們不做任何操作,運(yùn)行后,兩個(gè)視圖顯示的順序就是我們現(xiàn)在設(shè)置的這樣。但是假如我們對(duì)yellowView設(shè)置zPosition,哪怕很小的值,都會(huì)發(fā)現(xiàn)顯示的順序反了。
@interface ViewController () @property (weak, nonatomic) IBOutlet UIView *cyanView; @property (weak, nonatomic) IBOutlet UIView *yellowView;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.yellowView.layer.zPosition = 1.f; }現(xiàn)在的顯示效果如下:
雖說圖層基本沒有厚度,但是我們也盡量不要設(shè)置zPosition = 0.01f之類的。因?yàn)楦↑c(diǎn)類型的四舍五入可能導(dǎo)致難以察覺的麻煩。
4. Hit Testing
雖說CALayer不關(guān)心響應(yīng)鏈?zhǔn)录?#xff0c;但是它提供了一些方法讓我們處理事件-containsPoint:和-hitTest:。
4.1 -containsPoint:
-containsPoint:接受一個(gè)在本圖層坐標(biāo)系下的CGPoint,如果這個(gè)點(diǎn)在圖層frame范圍內(nèi)就返回YES.我們可以使用這個(gè)方法判斷是哪個(gè)圖層被觸摸了。
4.1.1 containsPoint 示例
代碼如下:
@interface ViewController () @property (weak, nonatomic) IBOutlet UIView *layerView; @property (nonatomic, strong) CALayer *blueLayer;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.blueLayer = [CALayer layer];self.blueLayer.frame = CGRectMake(20.f, 20.f, 100.f, 100.f);self.blueLayer.backgroundColor = [UIColor blueColor].CGColor;[self.layerView.layer addSublayer:self.blueLayer]; }- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {// 獲取觸摸點(diǎn)CGPoint point = [[touches anyObject] locationInView:self.view];// 轉(zhuǎn)換觸摸點(diǎn)在layerView的圖層的位置point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];// 判斷是否包含在layerview里面if ([self.layerView.layer containsPoint:point]) {point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];if ([self.blueLayer containsPoint:point]) {NSLog(@"點(diǎn)擊藍(lán)色圖層");} else {NSLog(@"點(diǎn)擊了白色圖層");}} }運(yùn)行點(diǎn)擊可以在控制臺(tái)看到NSLog的輸出信息。
4.2. -hitTest:
-hitTest:方法同樣接受一個(gè)CGPoint參數(shù),但是返回的是圖層本身,而不是BOOL類型。這使我們不用像-containsPoint:一樣每個(gè)子圖層去測(cè)試點(diǎn)擊的坐標(biāo)。如果這個(gè)點(diǎn)是在最外面的圖層,則返回nil。
4.2.1 hitTest示例
把上面-containsPoint:示例的代碼下面的部分修改一下即可:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {// 獲取點(diǎn)擊點(diǎn)CGPoint point = [[touches anyObject] locationInView:self.view];// 獲取這個(gè)點(diǎn)所在的圖層CALayer *layer = [self.layerView.layer hitTest:point];if (layer == self.blueLayer) {NSLog(@"點(diǎn)擊藍(lán)色圖層");} else if (layer == self.layerView.layer) {NSLog(@"點(diǎn)擊了白色圖層");} } 嘗試修改self.layerView的zPosition,會(huì)有不同的結(jié)果。有興趣的可以自己測(cè)試一下。-- 系列二完 --
總結(jié)
以上是生活随笔為你收集整理的图层几何学 -- iOS Core Animation 系列二的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL无法修改字段
- 下一篇: 页面从输入 URL 到页面加载显示完成