事件穿透

事件響應(yīng)和傳遞這篇文章中,講了iOS中的事件響應(yīng)和傳遞,今天在做項(xiàng)目的時(shí)候,正好碰到了一個(gè)應(yīng)用的場景,因此記錄下來。

需求

首頁頭部需要添加這樣一個(gè)視圖


image.png

點(diǎn)擊左右兩個(gè)按鈕,底部的滑塊跟著滑動(dòng),同時(shí)也可以拖動(dòng)滑塊到選中的按鈕位置。

思路和問題

看到這個(gè)設(shè)計(jì)圖一開始的想法就是,左右兩個(gè)按鈕,底部一個(gè)滑塊視圖,然后到做的時(shí)候,發(fā)現(xiàn)如果要做手勢(shì)拖拽的話,那么由于層級(jí)關(guān)系,滑塊肯定是在兩個(gè)按鈕下面的,如果要觸發(fā)滑動(dòng)手勢(shì),勢(shì)必會(huì)被按鈕的點(diǎn)擊事件阻止。


image.png

通過重寫hitTest方法解決

首先判斷點(diǎn)擊點(diǎn)是位于左側(cè)按鈕區(qū)域還是右側(cè)按鈕區(qū)域,在根據(jù)按鈕的選中狀態(tài)來判斷。
初始狀態(tài)時(shí)左側(cè)按鈕選中,右側(cè)沒選中,同時(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)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容