美文网首页动画设计学习iOStom
CALayer 添加事件处理的两种方法

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

作者: vvkeep | 来源:发表于2016-10-22 13:16 被阅读865次

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

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

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

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

    效果图:


    屏幕快照 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<UITouch>, 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<UITouch>, 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处理事件的机制类似)。

    相关文章

      网友评论

      • 小行为:很不错 hittest之前用过几次没用明白 这次还不错
      • 柳骏:全是swift😁😁😁

      本文标题:CALayer 添加事件处理的两种方法

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