iOS 不規則Button點選

即將成為型男的濤發表於2019-04-08

需求

利用圖片,實現一個如圖的按鈕組。

iOS 不規則Button點選

遇到的問題

如下圖所示:

  • 功能1、2、3、4的按鈕可以實現點選功能。但是在紅色方框四角的位置,也會響應相應的點選事件。
  • 紫色方框內四角區域點選時,響應的方法是功能5,而不是對應的功能。
iOS 不規則Button點選

解決思路

期望的結果

  • 尋找到合適的Button來處理點選事件

需要弄明白的問題

  • 事件在如何傳遞的?
  • 怎麼判斷誰來處理當前事件?

事件是如何傳遞的?

  1. 當使用者觸控實際螢幕時,會生成一個Touch Event,將此事件新增到UIApplication管理的事件佇列之中。
  2. UIApplication從事件佇列之中按順序取出事件分發到檢視去處理。
  3. 當事件被髮出以後,會從keyWindow開始,依次向上傳遞,包括Controller以及View,最後找到合適的檢視來響應事件。

可以看出:當一個事件發生後,事件會從父控制元件傳給子控制元件,也就是說由UIApplication -> UIWindow -> UIView -> initial view,以上就是事件的傳遞,也就是尋找最合適的view的過程。

涉及到兩個方法:

func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
func point(inside point: CGPoint, with event: UIEvent?) -> Bool
複製程式碼

當UIApplication傳送事件到keyWindow時,會呼叫 hitTest來尋找最合適的檢視處理事件。判斷邏輯如下:

  1. 首先判斷自身是否能夠響應觸控事件(userInteractionEnabled==true、hidden==true、alpha<=0.01不能響應觸控事件),若能響應則下一步,否則返回nil。

  2. 如果可以響應觸控事件,呼叫pointInside來判斷是否在顯示區域內,如果不在其中,pointInside返回false,同時hitTest返回nil。

  3. 如果 pointInside返回true,表示在當前的檢視之中,然後倒序遍歷該檢視的子檢視,重複上述步驟,直到某一檢視可以響應,hitTest:返回該檢視。

  4. 如果執行完上述步驟以後,沒有符合條件的檢視響應事件,則返回檢視本身,表示只有當前檢視符合條件,能夠處理該事件。

     Q:為什麼倒序遍歷?
     A:因為在subViews陣列中,最後新增的檢視,在檢視層級中處於最上方。
    複製程式碼

怎麼判斷誰來處理當前事件?

當知道的上面事件傳遞機制後,我們就能理清楚我們的Button處理事件的邏輯了:

  1. 自定義Button繼承自系統的Button。

  2. 重寫 point(inside point: CGPoint, with event: UIEvent?) -> Bool 方法。在其中判斷當前事件是否需要自身處理。

    • 判斷點是否在自身button.imageView的frame範圍內
    • 得到點選點在button.imageView中該點的顏色值
    • 如果得到的色值中alpha小於閥值,則返回false

具體程式碼可以檢視JTShapedButton原始碼

實現效果

iOS 不規則Button點選

相關文章