美文网首页GeekBand极客班-iOS开发
《iOS Core Animation》学习笔记:图层几何学

《iOS Core Animation》学习笔记:图层几何学

作者: Kevin丨Wang | 来源:发表于2016-02-07 11:20 被阅读125次

布局

UIView有三个比较重要的布局属性:frame、bounds、center。CALayer对应地叫做:frame、bounds、position。虽然UIView的center和CALayer的position属性代表同样的值。

  • frame代表了图层的外部坐标,也就是在父图层上占据的空间;
  • bounds代表了图层的内部坐标,{0,0通常是图层的左上角};
  • center和position代表了相对于父图层anchorPoint所在的位置;
UIView和CALayer的坐标系

视图的frame和图层的frame是相关联的,视图的frame发生改变,该视图对应的CALayer的frame也会发生变化。

frame属性值是根据bounds、position和transform计算出来的,当其中任意一个值发生变化,frame就会发生变化,当然改变frame值,也会影响到他们当中的值。

当对图层做变换的时候,例如旋转或缩放,frame实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,因此frame的宽高可能和bounds的宽高不再一致了。

锚点

视图的center属性和图层的position属性都指定anchorPoint相对于父图层的位置。

默认情况下,anchorPoint位于图层的中点,因此图层将会以这个点为中心放置。

anchorPoint用单位坐标来描述,也就是图层的相对坐标。因为图层的左上角是{0,0},右下角是{1,1},所以anchorPoint的默认坐标是{0.5,0.5}。

坐标系

和视图一样,图层在图层树当中也是相对于父图层按层级关系放置,一个图层的position依赖于它父图层的bounds,如果父图层发生了移动,它的所有子图层也会跟着移动。

Z坐标轴

和UIView严格的二维坐标系不同,CALayer存在于一个三维空间中。CALayer还有另外两个属性:zPosition和anchorPointZ,二者都是在Z轴上描述图层位置的浮点类型。

通常图层是根据它们子图层的sublayers出现的顺序来绘制的。

下面这个示例,是在Interface Builder中放置了一对视图,其中绿色视图会被绘制在红色视图的后面。

当然也可以提高绿色视图的zPosition来改变绘图的顺序。

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var greenView: UIView!
@IBOutlet weak var redView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.greenView.layer.zPosition = 1.0
  }
}
绿色视图被绘制在红色视图的前面

Hit Testing

CALayer并不关心任何响应链事件,所以不能直接处理触摸事件或手势。但是CALayer包含了两个方法帮助我们处理事件:containsPoint()和hitTest()。

containsPoint(_ p: CGPoint)方法接收一个在本图层坐标系下的CGPoint,如果这个点在图层的frame范围内就返回true。

import UIKit

class ViewController: UIViewController {

@IBOutlet var layerView: UIView!

private var blueLayer = CALayer()

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.blueLayer.frame = CGRectMake(50.0, 50.0, 100.0, 100.0)
    self.blueLayer.backgroundColor = UIColor.blueColor().CGColor
    
    self.layerView.layer.addSublayer(self.blueLayer)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    //get touch position relation to main view
    var point = touches.first?.locationInView(self.view)
    //convert point to the white layer's coordinates
    point = self.layerView.layer.convertPoint(point!, fromLayer: self.view.layer)
    //get layer using containsPoint method
    if self.layerView.layer.containsPoint(point!) {
        //convert point to blueLayer's coordinates
        point = self.blueLayer.convertPoint(point!, fromLayer: self.layerView.layer)
        if self.blueLayer.containsPoint(point!) {
           UIAlertView(title: "Inside Blue Layer", message: nil, delegate: nil, cancelButtonTitle: "OK").show()
        } else {
            UIAlertView(title: "Inside White Layer", message: nil, delegate: nil, cancelButtonTitle: "OK").show()
        }
    }
  }
}

hitTest方法同样接受一个CGPoint类型参数,但是返回值不是BOOL类型,而是图层本身,或者包含这个坐标点的叶子节点图层。

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var layerView: UIView!

private var blueLayer = CALayer()

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.blueLayer.frame = CGRectMake(50, 50, 100, 100)
    self.blueLayer.backgroundColor = UIColor.blueColor().CGColor
    
    self.layerView.layer.addSublayer(self.blueLayer)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    //get touch position
    let point = touches.first?.locationInView(self.view)
    //get touch layer
    let layer = self.layerView.layer.hitTest(point!)
    //get layer using hitTest
    if layer == self.blueLayer {
        UIAlertView(title: "Inside Blue Layer", message: nil, delegate: nil, cancelButtonTitle: "OK").show()
    } else if layer == self.layerView.layer {
        UIAlertView(title: "Inside White Layer", message: nil, delegate: nil, cancelButtonTitle: "OK").show()
    }
  }
}

注意:当调用图层的hitTest方法时,测试的顺序严格依赖图层树当中的图层顺序。

示例代码地址

相关文章

网友评论

    本文标题:《iOS Core Animation》学习笔记:图层几何学

    本文链接:https://www.haomeiwen.com/subject/apjykttx.html