iOS中事件傳遞的那點事情

一> 基礎(chǔ)概述

1> ios當(dāng)中常用的事件分為三種:

  • 觸摸事件
  • 加速計事件
  • 遠程控制事件

2> 什么是響應(yīng)者對象:

  • 繼承了UIResponds的對象我們稱它為響應(yīng)者對象, UIApplication伍派、UIViewController诉植、UIView都繼承自UIResponder, 因此它們都是響應(yīng)者對象昵观,都能夠接收并處理事件

3> 為什么說繼承了UIResponder就能夠處理事件?

  • 因為UIResponder內(nèi)部提供了以下方法來處理事件
    • 比如觸摸事件會調(diào)用以下方法:

      • - (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;
    • 加速計事件會調(diào)用:

      • - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
      • - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
      • - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
    • 遠程控制事件會調(diào)用 :

      • - (void)remoteControlReceivedWithEvent:(UIEvent *)event;

4> 如何監(jiān)聽UIView的觸摸事件?

  • 想要監(jiān)聽UIViiew的觸摸事件,首先第一步要自定義UIView, 因為只有實現(xiàn)了UIResponder的事件方法才能夠監(jiān)聽事件.

  • UIView的觸摸事件主要有:
    a) 一根或者多根手指開始觸摸view,系統(tǒng)會自動調(diào)用view的下面方法 : - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
    b) 一根或者多根手指在view上移動時啊犬,系統(tǒng)會自動調(diào)用view的下面方法 (隨著手指的移動灼擂,會持續(xù)調(diào)用該方法,也就是說這個方法會調(diào)用很多次) : - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
    c) 一根或者多根手指離開view剔应,系統(tǒng)會自動調(diào)用view的下面方法 : - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

  • 一次完整的觸摸過程语御,會經(jīng)歷3個狀態(tài):

    • 觸摸開始 :- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
    • 觸摸移動:- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
    • 觸摸結(jié)束:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
    • 觸摸取消(可能會經(jīng)歷):- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
    • 一次完整的觸摸過程中应闯,只會產(chǎn)生一個事件對象,4個觸摸方法都是同一個event參數(shù); 如果兩根手指同時觸摸一個view船万,那么view只會調(diào)用一次touchesBegan:withEvent: 方法骨田,touches參數(shù)中裝著2個UITouch對象; 如果這兩根手指一前一后分開觸摸同一個view,那么view會分別調(diào)用2次touchesBegan:withEvent:方法舱呻,并且每次調(diào)用時的touches參數(shù)中只包含一個UITouch對象

二> UITouch對象

1> UITouch對象概述

  • 當(dāng)用戶用一根手指觸摸屏幕時抵卫,會創(chuàng)建一個與手指相關(guān)聯(lián)的UITouch對象
  • 一根手指對應(yīng)一個UITouch對象

2> UITouch的作用

  • 保存著跟手指相關(guān)的信息介粘,比如觸摸的位置、時間雅采、階段
  • 當(dāng)手指移動時,系統(tǒng)會更新同一個UITouch對象宝鼓,使之能夠一直保存該手指在的觸摸位置
  • 當(dāng)手指離開屏幕時巴刻,系統(tǒng)會銷毀相應(yīng)的UITouch對象

3> UITouch對象屬性

  • window : 觸摸產(chǎn)生時所處的窗口
  • view : 觸摸產(chǎn)生時所處的視圖
  • tapCount : 短時間內(nèi)點按屏幕的次數(shù)胡陪,可以根據(jù)tapCount判斷單擊、雙擊或更多的點擊
  • timestamp : 記錄了觸摸事件產(chǎn)生或變化時的時間邑雅,單位是秒
  • phase : 當(dāng)前觸摸事件所處的狀態(tài)

4> UITouch對象方法

  • - (CGPoint)locationInView:(UIView *)view; : 返回值表示觸摸在view上的位置; 這里返回的位置是針對view的坐標(biāo)系的(以view的左上角為原點(0, 0))調(diào)用時傳入的view參數(shù)為nil的話淮野,返回的是觸摸點在UIWindow的位置
  • - (CGPoint)previousLocationInView:(UIView *)view; : 該方法記錄了前一個觸摸點的位置

三> UIEvent對象

1> UIEvent對象概述

  • 每產(chǎn)生一個事件吹泡,就會產(chǎn)生一個UIEvent對象
  • UIEvent:稱為事件對象,記錄事件產(chǎn)生的時刻和類型

2> UIEvent對象屬性

  • 事件類型

    • @property(nonatomic,readonly) UIEventType type;
    • @property(nonatomic,readonly) UIEventSubtype subtype;
  • 事件產(chǎn)生的時間 : @property(nonatomic,readonly) NSTimeInterval timestamp;

3> UIEvent對象方法

  • UIEvent還提供了相應(yīng)的方法可以獲得在某個view上面的觸摸對象(UITouch)

事件的產(chǎn)生和傳遞

  • 第一步: 尋找最適合的View

    • 發(fā)生觸摸事件后,系統(tǒng)會將該事件加入到一個由UIApplication管理的事件隊列中
    • UIApplication會從事件隊列中取出最前面的事件泪漂,并將事件分發(fā)下去以便處理萝勤,通常呐伞,先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow)
    • 主窗口會在視圖層次結(jié)構(gòu)中找到一個最合適的視圖來處理觸摸事件,這也是整個事件處理過程的第一步
    • 找到合適的視圖控件后趟径,就會調(diào)用視圖控件的touches方法來作具體的事件處理
      • 觸摸事件的傳遞是從父控件傳遞到子控件
        • 如果父控件不能接收觸摸事件癣防,那么子控件就不可能接收到觸摸事件
      • 如何找到最合適的控件來處理事件蕾盯?
        1. 自己是否能接收觸摸事件?
        2. 觸摸點是否在自己身上望拖?
        3. 從后往前遍歷子控件说敏,重復(fù)前面的兩個步驟
        4. 如果沒有符合條件的子控件盔沫,那么就自己最適合處理
      • UIView不接收觸摸事件的三種情況:
        1. 不接收用戶交互 : userInteractionEnabled = NO
        2. 隱藏 : hidden = YES
        3. 透明 : alpha = 0.0 ~ 0.01
  • 第二步: 如何尋找最適合的View

    • 當(dāng)一個事件傳遞給當(dāng)前的View時候, 系統(tǒng)就會調(diào)用 -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 方法
      • 作用 : 去尋找最適合的View
      • 何時調(diào)用 : 當(dāng)一個事件傳遞給當(dāng)前View,就會調(diào)用
      • 返回值 : 返回的是誰,誰就是最適合的View(就會調(diào)用最適合的View的touch方
    • 在系統(tǒng)調(diào)用hist, 系統(tǒng)內(nèi)部會調(diào)用pointInside方法
      • 作用 : 判斷當(dāng)前點在不在它調(diào)用View,(誰調(diào)用pointInside,這個View就是誰)
      • 何時調(diào)用 : 它是在hitTest方法當(dāng)中調(diào)用的
      • 注意:point點必須得要跟它方法調(diào)用者在同一個坐標(biāo)系里面
    • hitTest方法底層實現(xiàn)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{

    //1.判斷自己能否接收事件
    if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
        return nil;
    }
    //2.判斷當(dāng)前點在不在當(dāng)前View.
    if (![self pointInside:point withEvent:event]) {
        return nil;
    }
    //3.從后往前遍歷自己的子控件.讓子控件重復(fù)前兩步操作,(把事件傳遞給,讓子控件調(diào)用hitTest)
    int count = (int)self.subviews.count;
    for (int i = count - 1; i >= 0; i--) {
        //取出每一個子控件
        UIView *chileV =  self.subviews[i];
        //把當(dāng)前的點轉(zhuǎn)換成子控件從標(biāo)系上的點.
        CGPoint childP = [self convertPoint:point toView:chileV];
        UIView *fitView = [chileV hitTest:childP withEvent:event];
        //判斷有沒有找到最適合的View
        if(fitView){
            return fitView;
        }
    }
    
    //4.沒有找到比它自己更適合的View.那么它自己就是最適合的View
    return self;
}

觸摸事件處理的詳細過程

  1. 用戶點擊屏幕后產(chǎn)生的一個觸摸事件,經(jīng)過一系列的傳遞過程后惩歉,會找到最合適的視圖控件來處理這個事件

  2. 找到最合適的視圖控件后撑蚌,就會調(diào)用控件的touches方法來作具體的事件處理
    touchesBegan…
    touchesMoved…
    touchedEnded…

  3. 這些touches方法的默認做法是將事件順著響應(yīng)者鏈條向上傳遞搏屑,將事件交給上一個響應(yīng)者進行處理

  • 響應(yīng)者鏈條:是由多個響應(yīng)者對象連接起來的鏈條
  • 作用:能很清楚的看見每個響應(yīng)者之間的聯(lián)系辣恋,并且可以讓一個事件多個對象處理伟骨。
  • 響應(yīng)者對象:能處理事件的對象

四> 示例代碼

一) UIView的拖拽
  • 代碼思路:
    1. 自定義UIView,實現(xiàn)監(jiān)聽方法.
    2. 確定在TouchMove方法當(dāng)中進行操作,因為用戶手指在視圖上移動的時候才需要移動視圖携狭。
    3. 獲取當(dāng)前手指的位置和上一個手指的位置.
    4. 當(dāng)前視圖的位置 = 上一次視圖的位置 + 手指的偏移量
  • 關(guān)健代碼實現(xiàn):
    • 拿到UITouch就能獲取當(dāng)前點 : UITouch *touch = [touches anyObject];
    • 獲取當(dāng)前點 : CGPoint curP = [touch locationInView:self];
    • 獲取上一個點 : CGPoint preP = [touch previousLocationInView:self];
    • 獲取手指x軸偏移量 : CGFloat offsetX = curP.x - preP.x;
    • 獲取手指y軸偏移量 : CGFloat offsetY = curP.y - preP.y;
    • 移動當(dāng)前view : self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末继蜡,一起剝皮案震驚了整個濱河市逛腿,隨后出現(xiàn)的幾起案子单默,更是在濱河造成了極大的恐慌雕凹,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異李丰,居然都是意外死亡趴泌,警方通過查閱死者的電腦和手機嗜憔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門夺鲜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來币励,“玉大人食呻,你說我怎么就攤上這事澎现∥敉罚” “怎么了饼问?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我旦万,道長镶蹋,這世上最難降的妖魔是什么淆两? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮埃撵,結(jié)果婚禮上暂刘,老公的妹妹穿的比我還像新娘。我一直安慰自己芝发,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布苛谷。 她就那樣靜靜地躺著辅鲸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腹殿。 梳的紋絲不亂的頭發(fā)上独悴,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音锣尉,去河邊找鬼刻炒。 笑死,一個胖子當(dāng)著我的面吹牛自沧,可吹牛的內(nèi)容都是我干的坟奥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼拇厢,長吁一口氣:“原來是場噩夢啊……” “哼爱谁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起孝偎,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤访敌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后衣盾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寺旺,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡爷抓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了阻塑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓝撇。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖叮姑,靈堂內(nèi)的尸體忽然破棺而出唉地,到底是詐尸還是另有隱情,我是刑警寧澤传透,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布耘沼,位于F島的核電站,受9級特大地震影響朱盐,放射性物質(zhì)發(fā)生泄漏群嗤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一兵琳、第九天 我趴在偏房一處隱蔽的房頂上張望狂秘。 院中可真熱鬧,春花似錦躯肌、人聲如沸者春。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钱烟。三九已至,卻和暖如春嫡丙,著一層夾襖步出監(jiān)牢的瞬間拴袭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工曙博, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拥刻,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓父泳,卻偏偏與公主長得像般哼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子惠窄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容