在事件響應(yīng)和傳遞這篇文章中梅猿,講了iOS中的事件響應(yīng)和傳遞鞋邑,今天在做項(xiàng)目的時(shí)候诵次,正好碰到了一個(gè)應(yīng)用的場(chǎng)景,因此記錄下來(lái)枚碗。
需求
首頁(yè)頭部需要添加這樣一個(gè)視圖
點(diǎn)擊左右兩個(gè)按鈕逾一,底部的滑塊跟著滑動(dòng),同時(shí)也可以拖動(dòng)滑塊到選中的按鈕位置肮雨。
思路和問(wèn)題
看到這個(gè)設(shè)計(jì)圖一開(kāi)始的想法就是遵堵,左右兩個(gè)按鈕,底部一個(gè)滑塊視圖怨规,然后到做的時(shí)候陌宿,發(fā)現(xiàn)如果要做手勢(shì)拖拽的話(huà),那么由于層級(jí)關(guān)系椅亚,滑塊肯定是在兩個(gè)按鈕下面的限番,如果要觸發(fā)滑動(dòng)手勢(shì),勢(shì)必會(huì)被按鈕的點(diǎn)擊事件阻止呀舔。
通過(guò)重寫(xiě)hitTest方法解決
首先判斷點(diǎn)擊點(diǎn)是位于左側(cè)按鈕區(qū)域還是右側(cè)按鈕區(qū)域弥虐,在根據(jù)按鈕的選中狀態(tài)來(lái)判斷。
初始狀態(tài)時(shí)左側(cè)按鈕選中媚赖,右側(cè)沒(méi)選中霜瘪,同時(shí)滑塊位于左側(cè)。
如果觸摸點(diǎn)在右側(cè)按鈕區(qū)域惧磺,此時(shí)應(yīng)該走的流程是響應(yīng)右側(cè)按鈕事件颖对。
如果觸摸點(diǎn)在左側(cè)區(qū)域,此時(shí)左側(cè)區(qū)域是選中狀態(tài)磨隘,應(yīng)該響應(yīng)的是滑塊的拖動(dòng)事件缤底。
依照這個(gè)思路顾患,就有了下面的這段代碼
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let superHitPoint = self.convert(point, to: self.superview)
if superHitPoint.x <= self.frame.width {
if self.frame.minX > 0 { // 點(diǎn)擊左側(cè)按鈕,但是現(xiàn)在響應(yīng)的是右側(cè)按鈕个唧,原樣傳遞上去
return super.hitTest(point, with: event)
}
if self.isSelected {
return strikeView
} else {
return super.hitTest(point, with: event)
}
} else {
if self.frame.minX == 0 { // 同理
return super.hitTest(point, with: event)
}
if self.isSelected {
return strikeView
} else {
return super.hitTest(point, with: event)
}
}
}
這里要注意的一點(diǎn)是江解,由于事件響應(yīng)鏈?zhǔn)窍到y(tǒng)會(huì)從后往前遍歷子視圖,我們點(diǎn)擊任何一個(gè)區(qū)域徙歼,兩個(gè)按鈕都會(huì)響應(yīng)hitTest方法犁河,在判斷觸摸點(diǎn)的區(qū)域之后,還要判斷一下當(dāng)期響應(yīng)的按鈕是不是我們期望的按鈕魄梯,如果不是桨螺,則不作任何改動(dòng)。