日常工作中谁帕,我們直接操作UIView坝锰,一般不處理CALayer糙申,因?yàn)樘O果已經(jīng)為我們提供了優(yōu)美的UIView接口涨冀,但有一些功能UIView并沒(méi)有暴露出來(lái)的CALayer的功能:
- 陰影私恬、圓角债沮、帶顏色邊框
- 3D變換
- 線性動(dòng)畫
- ...(我也想不到了)
所以,使用我們要使用圖層相關(guān)視圖本鸣,不要?jiǎng)?chuàng)建獨(dú)立的圖層關(guān)系疫衩,還因?yàn)閁IView需要處理額外復(fù)雜的觸摸事件,但CALayer并不關(guān)心任何的響應(yīng)鏈?zhǔn)录俚拢圆荒苤苯犹幚碛|摸事件和手勢(shì)闷煤,但是它有contains和hitTest兩個(gè)方法可以幫助處理事件:
open func contains(_ p: CGPoint) -> Bool
接收一個(gè)在本圖層坐標(biāo)系下的CGPoint,如果這個(gè)點(diǎn)在圖層的frame 范圍內(nèi)就返回ture涮瞻,也就是說(shuō)使用此方法 可以判斷鲤拿,如下圖的 到底是藍(lán)色還是紅色的圖層被觸摸了,這需要把觸摸坐標(biāo)轉(zhuǎn)換成每個(gè)圖層的坐標(biāo)署咽,來(lái)判斷近顷,很不方便:效果圖和代碼如下:
效果圖:
屏幕快照 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層的點(diǎn)擊提示", 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?```方法同樣是接收一個(gè)CGPoint類型參數(shù),返回圖層本身宁否,或是包含這個(gè)坐標(biāo)點(diǎn)的節(jié)點(diǎn)圖層窒升。那樣我們既不需要人工的每個(gè)圖層轉(zhuǎn)換坐標(biāo),如果這個(gè)點(diǎn)在最外面圖層的范圍外慕匠,則返回nil饱须, 使用hitTest判斷被點(diǎn)擊圖層:
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層的點(diǎn)擊提示", 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)
}
} ```
注意:當(dāng)調(diào)用hitTest方法時(shí),測(cè)算的順序嚴(yán)格依賴于圖層樹當(dāng)中的圖層順序(和UIView處理事件的機(jī)制類似)台谊。