iOS UI高級之事件的分發

一、 事件的分發


1、當點擊屏幕的時候iOS設備的硬件會檢測(檢測的原理可以去查找資料,好像觸摸屏分爲電容屏和電阻屏,然後根據一些他們的特性來檢測的)到這個觸摸事件,然後打包到UIEvent對象防盜應用程序的事件分發隊列裏面(隊列:先進先出的特點,所有先進去的先執行)。UIApplication對象從隊列裏面取出最先進去的那個事件然後進行分發。一般會先傳遞給Window 。


解釋下這兩個方法:

方法1

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

方法2

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; 

當系統在調用第一個方法時會自動調用第二個方法,可以看出,第二個方法是判斷point那個點是不是在調用第一個方法的視圖上,如果是則方法1會返回當前這個視圖,否則返回nil事件的處理是根據返回的視圖來執行響應的處理方法的,等下講解關於事件鏈的傳遞,現在先講事件的分發。


來看看實例:UIWindow->myview->view1、view2

在window上面有一個子視圖myview,在my view視圖上有兩個子視圖view1,view2

假如說我們點擊了view2視圖


分析點擊view2之後事件的分發流程:

在點擊了view2之後 系統檢測到這個事件,然後放在了事件的隊列裏面,當uiapplication對象取出事件的時候向window發送消息,此時會調用window裏面的

(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 方法   (  編號:方法1)

在調用此方法的時候會在方法裏面調用- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 方法  (編號: 方法2)


當方法2判斷出point(觸摸屏幕的手指的位置)這個點在window上面 ,則會向直接加載到window上的視圖myiew發送消息,同時執行過程和上面一樣。先調用方法1.同時在方法1裏面調用方法2,檢測到point那個點是在myview上,則會向所有的子視圖也就是view1和view2發送消息,然後執行相同的操作。

注意:在向所有的子視圖發送消息的時候會先給top層那個發送(每個視圖上的子視圖的存放都是放在數組裏面的,先添加進去的下標小,後添加的大)。因爲,假如有多個視圖是重合在一起的情況,檢測到的點肯定都是在這些重合的視圖上的,但是返回那個視圖呢?一般我們只處理頂層那個我們看的到到視圖的響應,這個頂層點視圖肯定是最後添加上去的,所有在向所有的子視圖發送消息時會先發送給頂層那個,這樣假如有重合的情況下 在重疊的下面視圖就不必發送消息了,這樣效率會高。 我們也可以自定義方法1 來返回指定的視圖。

例如:在一個視圖view上有一個button和一個scrollview重疊,button在下面,scrollview在頂層。我們觸摸這個位置的時候方法1默認返回的是視圖scrollview,但是我們可以自定義讓它返回button視圖

我們在view這個視圖點implement裏面重寫方法1:

(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

//事件攔截 如果view有這些條件限制 則返回nill

if (self.alpha < 0.01 || self.userInteractionEnabled == NO || self.hidden == YES) {

        return nil;

    }

//判讀觸摸點是不是在這個視圖裏面 如果是 則遍歷子視圖 button和scrollview 系統默認的是先向top層的發送消息,然後返回它,這裏我們判斷出這個點在重疊的區域的時候讓它返回button

    if ([self pointInside:point withEvent:event]) {


NSArray *subViews = self.subviews;

        //從頂層開始遍歷  因爲如果有重疊的 情況 一般在下面層的 控件事件我們 不需要處理 只處理頂層那個

        for (NSInteger i = subViews.count - 1; i >= 0; i--) {

            UIView *view = subViews[i]; //第一次循環的時候 view = scrollview

// 將觸摸點轉化到scrollview 視圖上

            CGPoint convertPoint = [self convertPoint:point toView:view];

//這句比較關鍵 在重疊的情況下 系統默認的返回時top層那個視圖 這裏也就是scrollview

            UIView *view1 = [view hitTest:convertPoint withEvent:event];

return view1;//系統估計在這裏就直接返回top視圖了 但是我們要返回的不是這個 因此下面我們改變返回的視圖

            if (view1 != nil) {

                return subviews[i-1];//返回button

break;

            }


else

 return nill;


這裏我們 的事件的分發就講完了,實際上就是不斷的查找,直到找到觸摸的那個視圖。


關於響應者鏈歡迎點擊下一篇博客(由於篇幅的原因寫在下一篇)








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章