日常工作中,我们直接操作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处理事件的机制类似)。
网友评论