iOS 點擊事件傳遞及響應

轉載自:http://xfenglin.com/a/12007156660.html


1.iOS中的事件

iOS中的事件可以分爲3大類型:

  • 觸摸事件
  • 加速計事件
  • 遠程控制事件
    這裏我們只討論iOS中的觸摸事件。

1.1響應者對象(UIResponder)

在iOS中不是任何對象都能處理事件, 只有繼承了UIResponder的對象才能接收並處理事件,我們稱爲響應者對象

UIApplication,UIViewController,UIView都繼承自UIResponder,因此他們都是響應者對象, 都能夠接收並處理事件

UIResponder內部提供了以下方法來處理事件

觸摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

加速計事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

遠程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

2.iOS中事件的產生和傳遞

1.發生觸摸事件後,系統會將該事件加入到一個由UIApplication管理的隊列事件中

2.UIApplication會從事件隊列中取出最前面的事件,並將事件分發下去以便處理,通常會先發送事件給應用程序的主窗口(keyWindow)

3.主窗口會在視圖層次結構中找到一個最合適的視圖來處理觸摸事件

4.找到合適的視圖控件後,就會調用視圖控件的touches方法來作事件的具體處理:touchesBegin... touchesMoved...touchesEnded等

5.這些touches方法默認的做法是將事件順着響應者鏈條向上傳遞,將事件叫個上一個相應者進行處理

面我們舉個例子來演示下具體的傳遞過程,如圖:

150807180781051.png

一般事件的傳遞是從父控件傳遞到子控件的

例如:點擊了綠色的View,傳遞過程如下:UIApplication->Window->白色View->綠色View

點擊藍色的View,傳遞過程如下:UIApplication->Window->白色View->橙色View->藍色View

如果父控件接受不到觸摸事件,那麼子控件就不可能接收到觸摸事件

UIView不能接收觸摸事件的三種情況:

1.不接受用戶交互:userInteractionEnabled = NO;

2.隱藏:hidden = YES;

3.透明:alpha = 0.0~0.01

如何找到最合適的控件來處理事件呢?有以下準則

1.自己是否能接受觸摸事件

2.觸摸點是否在自己身上

3.從後往前遍歷子控件,重複上面的兩個步驟

4.如果沒有符合條件的子控件,那麼自己最適合處理

例如:

150807180781052.png

說明一下控件的添加順序:白1->綠2->橙2->藍3->紅3->黃4

這裏點擊了橙色的那塊區域,事件傳遞判斷過程如下:

1.UIApplication從事件隊列中取出事件分發給UIWindow

2.UIWindow判斷自己是否能接受觸摸事件,可以

3.UIWindow判斷觸摸點是否在自己身上,是的。

4.UIWindow從後往前便利自己的子控件,取出白1

5.白1都滿足最上面兩個條件,遍歷子控件橙2

6.橙2都滿足最上面兩個條件,遍歷子控件,先取出紅3

7.紅3不滿足條件2,取出藍3

8.藍3也不滿足條件2,最後最合適的控件是橙2

2.1( 重難點)如何尋找最合適的view

應用如何找到最合適的控件來處理事件?
1.首先判斷主窗口(keyWindow)自己是否能接受觸摸事件
2.觸摸點是否在自己身上
3.從後往前遍歷子控件,重複前面的兩個步驟(首先查找數組中最後一個元素)
4.如果沒有符合條件的子控件,那麼就認爲自己最合適處理

詳述:1.主窗口接收到應用程序傳遞過來的事件後,首先判斷自己能否接手觸摸事件。如果能,那麼在判斷觸摸點在不在窗口自己身上
            2.如果觸摸點也在窗口身上,那麼窗口會從後往前遍歷自己的子控件(遍歷自己的子控件只是爲了尋找出來最合適的view)
            3.遍歷到每一個子控件後,又會重複上面的兩個步驟(傳遞事件給子控件,1.判斷子控件能否接受事件,2.點在不在子控件上)
            4.如此循環遍歷子控件,直到找到最合適的view,如果沒有更合適的子控件,那麼自己就成爲最合適的view。

找到最合適的view後,就會調用該view的touches方法處理具體的事件。所以,只有找到最合適的view,把事件傳遞給最合適的view後,纔會調用touches方法進行接下來的事件處理。
找不到最合適的view,就不會調用touches方法進行事件處理。
注意:之所以會採取從後往前遍歷子控件的方式尋找最合適的view只是爲了做一些循環優化。因爲相比較之下,後添加的view在上面,降低循環次數。

3.事件響應

上文介紹了事件的傳遞過程,找到合適的控件之後就要進行響應了,這裏先介紹一下響應者鏈條:響應者鏈條其實就是很多響應者對象(繼承自UIResponder的對象)一起組合起來的鏈條稱之爲響應者鏈條

一般默認做法是控件將事件順着響應者鏈條向上傳遞,將事件交給上一個響應者進行處理。那麼如何判斷當前響應者的上一個響應者是誰呢?有以下兩個規則:

1.判斷當前是否是控制器的View,如果是控制器的View,上一個響應者就是控制器

2.如果不是控制器的View,上一個響應者就是父控件

響應過程如下圖:

150807180781053.png

如果控制器也不響應響應touches方法,就交給UIWindow。如果UIWindow也不響應,交給UIApplication,如果都不響應事件就作廢了。

最後總結來說一次完整的觸摸事件的傳遞響應過程爲:

UIApplication-->UIWindow-->遞歸找到最合適處理的控件-->控件調用touches方法-->判斷是否實現touches方法-->沒有實現默認會將事件傳遞給上一個響應者-->找到上一個響應者-->找不到方法作廢

一句話總結整個過程是:觸摸或者點擊一個控件,然後這個事件會從上向下(從父->子)找最合適的view處理,找到這個view之後看他能不能處理,能就處理,不能就按照事件響應鏈向上(從子->父)傳遞給父控件

事件的傳遞和響應的區別:

事件的傳遞是從上到下(父控件到子控件),事件的響應是從下到上(順着響應者鏈條向上傳遞:子控件到父控件。

參考資料:

史上最詳細的iOS之事件的傳遞和響應機制

iOS中的事件傳遞和響應者鏈條


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