CALayer 添加事件处理的两种方法

日常工作中,我们直接操作UIView,一般不处理CALayer,因为苹果已经为我们提供了优美的UIView接口,但有一些功能UIView并没有暴露出来的CALayer的功能:

  • 阴影、圆角、带颜色边框
  • 3D变换
  • 线性动画
  • ...(我也想不到了)

所以,使用我们要使用图层相关视图,不要创建独立的图层关系,还因为UIView需要处理额外复杂的触摸事件,但CALayer并不关心任何的响应链事件,所以不能直接处理触摸事件和手势,但是它有contains和hitTest两个方法可以帮助处理事件:

open func contains(_ p: CGPoint) -> Bool 接收一个在本图层坐标系下的CGPoint,如果这个点在图层的frame 范围内就返回ture,也就是说使用此方法 可以判断,如下图的 到底是蓝色还是红色的图层被触摸了,这需要把触摸坐标转换成每个图层的坐标,来判断,很不方便:效果图和代码如下:

效果图:


CALayer 添加事件处理的两种方法_第1张图片
屏幕快照 2016-10-22 下午1.00.23.png

代码:

class ViewController: UIViewController {

    lazy var layerView: UIView = {
       let layerView = UIView.init(frame: CGRect(x: 50.0, y: 50.0, width: 200.0, height: 200.0))
        layerView.backgroundColor = UIColor.red
        return layerView
    }()
    
    var blueLayer: CALayer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(layerView)
        blueLayer = CALayer.init()
        
        guard let blueLayer = blueLayer else {
            return
        }
        blueLayer.frame = CGRect(x: 50.0, y: 50.0, width: 100.0, height: 100.0)
        blueLayer.backgroundColor = UIColor.blue.cgColor
        layerView.layer.addSublayer(blueLayer)
    }
    
    
    override func touchesBegan(_ touches: Set, with event: UIEvent?) {
        var point = touches.first?.location(in: view)
        point = layerView.layer.convert(point!, from: view.layer)
        if layerView.layer.contains(point!) {
            point = blueLayer?.convert(point!, from: layerView.layer)
            
            if blueLayer!.contains(point!) {
                let alertController = UIAlertController(title: "提示", message: "layer层的点击提示", preferredStyle: UIAlertControllerStyle.alert)
                let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)
                let okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.default, handler: nil)
                alertController.addAction(cancelAction)
                alertController.addAction(okAction)
                present(alertController, animated: true, completion: nil)
            }
        }
    } ```

 ```open func hitTest(_ p: CGPoint) -> CALayer?```方法同样是接收一个CGPoint类型参数,返回图层本身,或是包含这个坐标点的节点图层。那样我们既不需要人工的每个图层转换坐标,如果这个点在最外面图层的范围外,则返回nil, 使用hitTest判断被点击图层:
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
    let point = touches.first?.location(in: view)
    let layer = layerView.layer.hitTest(point!)
    if layer == blueLayer {
        let alertController = UIAlertController(title: "提示", message: "layer层的点击提示", preferredStyle: UIAlertControllerStyle.alert)
        let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)
        let okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.default, handler: nil)
        alertController.addAction(cancelAction)
        alertController.addAction(okAction)
        present(alertController, animated: true, completion: nil)
    }
} ```

注意:当调用hitTest方法时,测算的顺序严格依赖于图层树当中的图层顺序(和UIView处理事件的机制类似)。

你可能感兴趣的:(CALayer 添加事件处理的两种方法)