国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

事件處理原理(IOS篇)bysixleaves

2019-11-14 18:44:43
字體:
來源:轉載
供稿:網友

前言

了解IOS事件處理的本質關鍵要先掌握幾個概念。首先是事件的派發(Event Delivery)的過程, 一個是響應者鏈條如何構成

事件的派發:

Q1: 你有沒有想過,如果你一個屏幕中有多個的View。當你點擊某個view的時候, 這個點擊事件是如何傳遞到這個View身上的?

S1: 正是因為當我們點擊屏幕上某個點的時候, IOS會檢查到手指觸摸操作(Touch),并生產一個UITouch對象,將其打包成一個UIEvent對象。然后將其放入當前活動的application事件對列 UIApplication會從事件對列中按照對列的順序,取出觸摸事件傳遞給UIWindow處理,UIWindow對象會使用hitTest:withEvent:方法來尋找此次的觸摸操作初始點所在的最深層次的視圖(View).**即調用hitTest:withEvent會返回該觸摸點所在的最深層次的視圖。 **

Q2:hitTest:withEvent如何實現找到最深層次的視圖,也就是目的視圖。

S2: 這就要說到深度優先搜索算法,hitTest:withEvent正是基于深度優先搜索的方式來找到最深層次的視圖對象。所以我來介紹以下深度優先算法的思想, 要理解該思想, 你首先要有樹結構這一概念(參見數據結構中的樹結構)。該思想是從根節點開始遍歷樹,而遍歷的順序是采用把下一個子節點當做當前根節點繼續遍歷。所以其是先遍歷到最樹的最深的一層再層層回朔到根節點,接著在把另外一個子節點當做當前根節點繼續遍歷。正是基于這種思想, 所以我們可以很方便的采用遞歸來實現。如果還是不理解,有兩種辦法幫助你,一種是去找深度優先的動態圖,一看就懂了我說的。另外一種方法是去復習數據結構與算法。

Q3:既然hitTest:withEvent利用了深度優先的思想來做,并采用遞歸的做法來做。那么遞歸結束的條件是啥?也就是說什么條件下事件不會向下派發?

S3:根據官方文檔給出的條件是(hidden == YES || userInteractionEnabled == YES || alpha < 0.01 || subViews.bounds > subViews.superView.bounds)

何為響應者鏈條

Q4: 也許你經常聽別人在說響應者鏈條,但是還是云里霧里。這邊我就給你解釋下

S4: 首先先明確何為響應者? ===> 在ios開發中繼承自UIResponder的類或子類就是響應者,顧明思意,響應者是用來相應事件的(觸摸事件、運動事件、遠程遙控事件)。所以所謂的響應者鏈條就是一系列響應者構成的層次結構。

Q5: 那么響應者鏈條是如何表示這種層次結構的呢?

S5: 響應者鏈條是通過nextResponder方法的返回值來組成這種層次結構的 ,蘋果有一段官方解釋如下:

The UIResponder class does not store or set the next responder automatically, instead returning nil by default. Subclasses must override this method to set the next responder. UIView implements this method by returning the UIViewController object that manages it (if it has one) or its superview (if it doesn’t); UIViewController implements the method by returning its view’s superview; UIWindow returns the application object, and UIApplication returns nil.

也就是說,響應者對象是不會自動設置和存儲下一個響應者,默認情況下是直接返回nil。而繼承自UIResponder的子類必須重寫這個方法來設置下一個響應者,并且需要遵循如下規范

    1. 如果子類是UIView,那么其getter方法的nextResponder必須返回其UIViewController對象。       如果不存在控制器,則返回其父視圖對象。    2. 如果子類是UIViewController對象, 那么重寫的nextResponder方法必須返回其view視圖的父視圖對象。    3. 如果子類是UIWindow對象,那么重寫的nextResponder方法返回的是application對象    4. 如果子類是UIApplication對象,那么重寫的nextResponder方法,返回nil。

通過上述規范,結合下圖,你應該能很容易理解所謂的響應者鏈條如何構成:

Q6: 疑問,假設我有一個自定義的SWPButton,而且給其設置了連線action(也就是點擊按鈕后回調的函數)。我們知道當我們點擊按鈕的時候系統會捕捉到這個事件,并將其派發下來。那么我們如何做到讓按鈕不響應這個action而是只響應這個事件。

  • S6: 本質上系統默認實現的touchesBegan:withEvent:方法是做了兩件事件, 或者說有繼承子UIResponder的系統定義的類,都默認實現了以下兩件事情
    • 第一件事情是: 調用[super touchesBegan:withEvent]讓父類有機會來處理該事件。 同時傳遞了事件,讓父類能根據事件處理相應的action回調,比如父類會在這里面處理action(也就是點擊按鈕時候的回調)
    • 第二件事情是: 拋給上一個響應者,讓上一個響應者也能處理該事件。同時傳遞了該事件。這兩個是不一樣的,前者是針對父類,后者是針對響應者鏈條。二者缺一不可。再者,有的人會說只要實現了[super toucesBegan:withEveent]就會將事件拋開上一個響應者,這是不嚴謹的說法。因為這是因為系統已經為所有繼承自UIResponder的子類,做了上面那兩件事件。比如 ,當你自定義一個SWPButton該類繼承自UIButton,那么當你重寫touchesBegan方法的時候,在你們調用[super touchesBegan:withEvent]這個方法時候,系統自定義的UIButton類已經具備這個功能,所以其能完成向上拋。而當我們定義一個純潔的SWPButton直接繼承自UIResponder, 那么我們必須自己實現向上拋這個事情,而不是只調用[super touchesBegan:withEvent]。
      華麗的分割線,以下是度對Q6的解答因為我們繼承自UIButton,所以要截斷該action的回調,我們只需重寫touchesBegan:withEvent方法。并且不做第一件事件,那么也就不會將事件傳遞給Button對象,button也就無法響應相應的action。
#import "SWPButton.h"@implementation SWPButton- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {        [self.nextResponder touchesBegan:touches withEvent:event];}@end

所以此時如果你點擊按鈕, 其會先調用這個自定義按鈕的touchesBegan, 因為點擊事件傳遞到了button身上,所以會調用touchesBegan來響應該事件,但是該事件不在交給父類處理,所以不會調用action。只會繼續將其拋給上一個響應者。

放大招(根據View來找到其所在控制器):

@implementation UIView (ParentController)-(UIViewController*)parentController{    UIResponder *responder = [self nextResponder];    while (responder) {    if ([responder isKindOfClass:[UIViewController class]]) {        return (UIViewController*)responder;    }    responder = [responder nextResponder];    }    return nil;}@end
思路很簡單,就是利用響應者鏈條來尋找UIViewController.那么這個UIView的上一個響應者只有兩種情況,一種是依然是一個UIView對象或其子對象,也就是說它是這個UIView的子View。一種是這個  UIView的控制器。所以我們才需要循環判斷,然后不斷找(循環),直到第一次找到的控制器,就是這個UIView所在的控制器。如果找不到,就返回nil。

是不是更加理解你事件派發的過程,所謂的事件派發過程,其實就是尋找最合適的視圖的時候,事件隨著這個尋找過程,不斷傳遞。為什么要傳遞UIEvent呢?因為通過它給以獲得Touch對象,而通過Touch對象我們可以獲得初始觸摸點。也就是說hitTest:withEvent主要實現的功能是,傳遞事件,找到最合適的視圖。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 金湖县| 邯郸市| 白河县| 沁水县| 南川市| 钟祥市| 石林| 黄梅县| 泾阳县| 庆城县| 资溪县| 建平县| 都江堰市| 洞头县| 苏尼特左旗| 准格尔旗| 绩溪县| 乌海市| 恭城| 和林格尔县| 罗田县| 吉木乃县| 伊宁市| 洞口县| 佛教| 阿拉善左旗| 芦溪县| 广水市| 鱼台县| 油尖旺区| 和政县| 镇坪县| 清新县| 峡江县| 仁化县| 新竹县| 镇雄县| 出国| 兰州市| 南溪县| 浠水县|