在事件響應和傳遞這篇文章中,講了iOS中的事件響應和傳遞,今天在做項目的時候,正好碰到了一個應用的場景,因此記錄下來。
需求
首頁頭部需要添加這樣一個視圖
image.png
點擊左右兩個按鈕,底部的滑塊跟著滑動,同時也可以拖動滑塊到選中的按鈕位置。
思路和問題
看到這個設(shè)計圖一開始的想法就是,左右兩個按鈕,底部一個滑塊視圖,然后到做的時候,發(fā)現(xiàn)如果要做手勢拖拽的話,那么由于層級關(guān)系,滑塊肯定是在兩個按鈕下面的,如果要觸發(fā)滑動手勢,勢必會被按鈕的點擊事件阻止。
image.png
通過重寫hitTest方法解決
首先判斷點擊點是位于左側(cè)按鈕區(qū)域還是右側(cè)按鈕區(qū)域,在根據(jù)按鈕的選中狀態(tài)來判斷。
初始狀態(tài)時左側(cè)按鈕選中,右側(cè)沒選中,同時滑塊位于左側(cè)。
如果觸摸點在右側(cè)按鈕區(qū)域,此時應該走的流程是響應右側(cè)按鈕事件。
如果觸摸點在左側(cè)區(qū)域,此時左側(cè)區(qū)域是選中狀態(tài),應該響應的是滑塊的拖動事件。
依照這個思路,就有了下面的這段代碼
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 { // 點擊左側(cè)按鈕,但是現(xiàn)在響應的是右側(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)
}
}
}
這里要注意的一點是,由于事件響應鏈是系統(tǒng)會從后往前遍歷子視圖,我們點擊任何一個區(qū)域,兩個按鈕都會響應hitTest方法,在判斷觸摸點的區(qū)域之后,還要判斷一下當期響應的按鈕是不是我們期望的按鈕,如果不是,則不作任何改動。