iOS不規則控制元件的點選事件

發表於2015-04-09

我們有時候會碰到這樣的需求,比如我們某個選單是圓形的,或者某個選單是環形的,由於一些情況普通使用者很少能感知到,可能導致我們對非矩形控制元件的事件處理都按照矩形的區域來處理了,雖然這樣的實現也沒有問題,但是如果有一些極端的不規則控制元件出現的時候,可能矩形的處理區域就無法滿足需求,我們就需要一種更加精確的處理方式,來決定我們的事件到底分發給哪個subview。

差不多2年前的時候,國內很多TabBar的設計中間都有一個凸起的部分,當時還是很流行,如下圖所示

這種UI實現起來也比較簡單,我們只需要一張背景圖片加上幾個按鈕的圖片就可以了,至於中間的凸起部分,我們一般有兩種處理方式:

1、設定TabBar的frame為圖二所示的區域,然後中間的按鈕的座標設定成負數(iOS中,如果設定clipsToBounds=NO的情況,是可以顯示出超過View區域的subview)。

2、設定TabBar的frame為圖三所示的區域,然後剩下的正常設定

這兩種方式都可以實現這種設計,但是都存在問題。圖二中,由於中間的按鈕有一部分不在TabBar的區域內,不再TabBar的區域不能響應事件,所以綠色陰影部分點選了之後無法達到預期的效果;圖三中,TabBar透明區域遮住了後面的TableView的一部分,所以在圖三綠色陰影區域內,無法響應TableView的滾動事件。相比之下,圖三的處理方式對使用者的操作影響會少一些,所以大部分都選擇了圖三所示的方式,當然這也看情況而視,主要是根據你凸起的大小來決定。

我們有沒有一種方法來解決這種問題呢?即我們既希望使用者點選凸起的地方能夠響應TabBar事件,又希望在圖三綠色陰影內能讓TableView進行滾動。

答案顯然是有的。

之前寫過幾篇文章,介紹iOS的事件分發(hitTest),我們在這裡就需要用到這些知識了。我們需要在確定hitTestView的時候告訴UIKit,如果觸控區域在這些地方,就把事件分發給TabBar,在那些地方,你就不要分發給TabBar,你直接忽略TabBar,當作TabBar不存在就行了。

我們來實現一下如上所示的需求,我們首先選擇圖三所示的方法自定義TabBar。也就是定義TabBar的frame比較大,然後往裡面新增元件,新增元件的程式碼比較零碎,就不在這裡貼上了。

補充一點知識,我們如何確定點選區域在如下圖所示的區域內呢? 

這就是一點簡單的數學知識。以TabBar左上角作為原點iOS檢視座標系中,假設凸起部分半徑為40,超出的高度是20,圓心座標為P(160, 40),則y>20的區域必須是TabBar的區域,而且距離中間凸起圓形區域的半徑<40的區域也是TabBar的點選區域。也就是最終的這個不規則圖形是由一個矩形和一個原疊和而成的。

根據我們的到的觸控點P1(x,y), 則如果 y > 20 || distance(P1,P) < 40,則返回響應的hitTestView為TabBar,否則,則返回nil(返回nil則認為當前TabBar不響應事件)。(兩點間的距離的計算方式在這裡就不說了)

上程式碼了

程式碼很簡單的就實現了我們的需求,點選上圖所示紅色區域內的,TabBar去響應事件,反之,則交給TabBar下面的View去響應事件(hitTestBlock的這一部分可以直接參考之前提過的部落格)。

關於TabBar的就說這麼多,大家可以通過我的GitHub來下載Demo。Demo中的如果大家想更精確的測試,建議用模擬器+滑鼠來操作。

我們根據如上的方法,就能得到一個解決方案。對於不規則的點選區域,我們只需要重寫當前View的hitTest方法,然後根據一些數學公式來檢測,如果滿足條件,則返回當前View,否則,返回nil就可以了,當然前提是我們View的大小要覆蓋我們期望的的點選區域,不能出現一些超出View區域的subview。

PS.有時候我們出現一些點選無法響應的情況,我們可以通過設定clipsToBounds=YES來驗證是否是因為超出了父View的區域而導致的。

根據如上的思路,我來實現一個圓形的按鈕,要求只有點選圓形內才響應事件,否則則不響應按鈕事件

這個Demo的測試大家可以通過如上所示的git中下載,直接點選第二個標籤測試就OK了~~

HitTestDemo地址

大家可以通過修改SKRoundButton,自行實現環形的按鈕,無非就是數學公式而已,沒有其他複雜的地方。

相關文章