iOS 中的事件

01-UIView的拖拽

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

1.觸摸事件
2.加速計(jì)事件
3.遠(yuǎn)程控制事件

2.什么是響應(yīng)者對(duì)象?

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

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

因?yàn)閁IResponder內(nèi)部提供了以下方法來處理事件

        比如觸摸事件會(huì)調(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;
        加速計(jì)事件會(huì)調(diào)用:
        - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
        - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
        - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
        遠(yuǎn)程控制事件會(huì)調(diào)用:
        - (void)remoteControlReceivedWithEvent:(UIEvent *)event;

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

想要監(jiān)聽UIViiew的觸摸事件,首先第一步要自定義UIView, 因?yàn)橹挥袑?shí)現(xiàn)了UIResponder的事件方法才能夠監(jiān)聽事件.

UIView的觸摸事件主要有:
       一根或者多根手指開始觸摸view,系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法.
       - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
       一根或者多根手指在view上移動(dòng)時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法
       (隨著手指的移動(dòng),會(huì)持續(xù)調(diào)用該方法,也就是說這個(gè)方法會(huì)調(diào)用很多次)
       - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
       一根或者多根手指離開view,系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法
       - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
       參數(shù)說明:
           touches:
               touches中存放的都是UITouch對(duì)象,它是一個(gè)NSSet集合.
               UITouch對(duì)象它就是用來保存手指相關(guān)聯(lián)的信息.包括位置,時(shí)間,階段等信息.
               每一個(gè)手指對(duì)應(yīng)著一個(gè)UITouch對(duì)象.
               這個(gè)UITouch是系統(tǒng)自動(dòng)幫我們創(chuàng)建的,當(dāng)手指移動(dòng)時(shí),系統(tǒng)會(huì)更新同一個(gè)UITouch對(duì)象,
               使它能夠一直保存該手指在的觸摸位置
               通過獲取UITouch屬性,我們可以獲得觸摸產(chǎn)生時(shí)所處的窗口,觸摸的View,時(shí)間,點(diǎn)擊的次數(shù)等,
               這些都可以在通過UITouch獲取.
               還可以通過UITouch提供的方法獲取當(dāng)前手指所在的點(diǎn),以及上一個(gè)手指所在的點(diǎn).
               取當(dāng)前手指所在的點(diǎn)
               - (CGPoint)locationInView:(UIView *)view;
               獲取上一個(gè)觸摸點(diǎn)的位置.
               - (CGPoint)previousLocationInView:(UIView *)view;
           event:
               每產(chǎn)生一個(gè)事件,就會(huì)產(chǎn)生一個(gè)UIEvent對(duì)象
               UIEvent:稱為事件對(duì)象,記錄事件產(chǎn)生的時(shí)刻和類型
       一次完整的觸摸過程,會(huì)經(jīng)歷3個(gè)狀態(tài):
       觸摸開始:- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
       觸摸移動(dòng):- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
       觸摸結(jié)束:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
       觸摸取消(可能會(huì)經(jīng)歷):- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
       一次完整的觸摸過程中,只會(huì)產(chǎn)生一個(gè)事件對(duì)象,4個(gè)觸摸方法都是同一個(gè)event參數(shù)
       如果兩根手指同時(shí)觸摸一個(gè)view,那么view只會(huì)調(diào)用一次touchesBegan:withEvent:方法,touches參數(shù)中裝著2個(gè)UITouch對(duì)象
       如果這兩根手指一前一后分開觸摸同一個(gè)view,那么view會(huì)分別調(diào)用2次touchesBegan:withEvent:方法,
       并且每次調(diào)用時(shí)的touches參數(shù)中只包含一個(gè)UITouch對(duì)象

5.UIView拖拽思路?

1.自定義UIView,實(shí)現(xiàn)監(jiān)聽方法.
2.確定在TouchMove方法當(dāng)中進(jìn)行操作,因?yàn)橛脩羰种冈谝晥D上移動(dòng)的時(shí)候才需要移動(dòng)視圖。
3.獲取當(dāng)前手指的位置和上一個(gè)手指的位置.
4.當(dāng)前視圖的位置 = 上一次視圖的位置 + 手指的偏移量

        關(guān)健代碼實(shí)現(xiàn):
            拿到UITouch就能獲取當(dāng)前點(diǎn)
            UITouch *touch = [touches anyObject];
            獲取當(dāng)前點(diǎn)
            CGPoint curP = [touch locationInView:self];
            獲取上一個(gè)點(diǎn)
            CGPoint preP = [touch previousLocationInView:self];
            獲取手指x軸偏移量
            CGFloat offsetX = curP.x - preP.x;
            獲取手指y軸偏移量
            CGFloat offsetY = curP.y - preP.y;
            移動(dòng)當(dāng)前view
            self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);

02-事件的產(chǎn)生與傳遞

1.事件是怎么樣產(chǎn)生與傳遞的?

1.當(dāng)發(fā)生一個(gè)觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè) UIApplication 管理的事件隊(duì)列中.
2.UIApplication會(huì)從事件隊(duì)列中取出最前面的事件,并將事件分發(fā)下去以便處理.
3.主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件, 觸摸事件的傳遞是從父控件傳遞到子控件的.
4.如果一個(gè)父控件不能接收事件,那么它里面的了子控件也不能夠接收事件.

2.一個(gè)控件什么情況下不能夠接收事件.

1.不接收用戶交互時(shí)不能夠處理事件 userInteractionEnabled = NO
2.當(dāng)一個(gè)控件隱藏的時(shí)候不能夠接收事件 Hidden = YES 的時(shí)候
3.當(dāng)一個(gè)控件為透明白時(shí)候也不能夠接收事件   
注意:UIImageView的userInteractionEnabled默認(rèn)就是NO,因此UIImageView以及它的子控件默認(rèn)是不能接收觸摸事件的

03-如何尋找最合適的View.

1.如何尋找最合適的View?

主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件.
那如何找到最合適的View呢?
1.先判斷自己是否能夠接收觸摸事件,如果能再繼續(xù)往下判斷,
2.再判斷觸摸的當(dāng)前點(diǎn)在不在自己的身上.
3.如果在自己身上,它會(huì)從后往前遍歷子控件,遍歷出每一個(gè)子控件后,重復(fù)前面的兩個(gè)步驟.
4.如果沒有符合條件的子控件,那么它自己就是最適合的View.

04-hitTest方法與PointInside方法

作用:尋找最適合的View
參數(shù):當(dāng)前手指所在的點(diǎn).產(chǎn)生的事件
返回值:返回誰, 誰就是最適合的View.
什么時(shí)候用調(diào)用:只要一個(gè)事件,傳遞給一個(gè)控件時(shí), 就會(huì)調(diào)用這個(gè)控件的hitTest方法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

作用:判斷point在不在方法調(diào)用者上
point:必須是方法調(diào)用者的坐標(biāo)系
什么時(shí)候調(diào)用:hitTest方法底層會(huì)調(diào)用這個(gè)方法,判斷點(diǎn)在不在控件上.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    return YES;
}


hitTest底層實(shí)現(xiàn):
    
    1.判斷當(dāng)前能不能接收事件
      if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) 
      return  nil;
    2.判斷觸摸點(diǎn)在不在當(dāng)前的控件上
     if(![self pointInside:point withEvent:event]) return nil;
    3.從后往前遍歷自己的子控件
    int count = (int)self.subviews.count;
    for (int i = count - 1; i >= 0;i-- ) {
    
    UIView *childV = self.subviews[i];
    把當(dāng)前坐標(biāo)系上的點(diǎn)轉(zhuǎn)換成子控件坐標(biāo)系上的點(diǎn).
    CGPoint childP = [self convertPoint:point toView:childV];
    判斷自己的子控件是不是最適合的View
    UIView *fitView = [childV hitTest:childP withEvent:event];
    如果子控件是最適拿的View,直接返回
        if (fitView) {
            return  fitView;
        }
    }

    4.自己就是最適合的View
        return self.

05-事件響應(yīng)

用戶點(diǎn)擊屏幕后產(chǎn)生的一個(gè)觸摸事件,經(jīng)過一系列的傳遞過程后,會(huì)找到最合適的視圖控件來處理這個(gè)事件,
找到最合適的視圖控件后,就會(huì)調(diào)用控件的touches方法來作具體的事件處理
那這些touches方法的默認(rèn)做法是將事件順著響應(yīng)者鏈條向上傳遞,將事件交給上一個(gè)響應(yīng)者進(jìn)行處理

什么是響應(yīng)者鏈條?
是由多個(gè)響應(yīng)者對(duì)象連接起來的鏈條.

什么是響應(yīng)者對(duì)象?
繼承了UIResponder對(duì)象我們稱之為響應(yīng)者對(duì)象,也就是能處理事件的對(duì)象

事件傳遞的完整過程?
在產(chǎn)生一個(gè)事件時(shí),系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中,
UIApplication會(huì)從事件隊(duì)列中取出最前面的事件,將它傳遞給先發(fā)送事件給應(yīng)用程序的主窗口.
主窗口會(huì)調(diào)用hitTest方法尋找最適合的視圖控件,找到后就會(huì)調(diào)用視圖控件的touches方法來做具體的事情.
當(dāng)調(diào)用touches方法,它的默認(rèn)做法, 就會(huì)將事件順著響應(yīng)者鏈條往上傳遞,
傳遞給上一個(gè)響應(yīng)者,接著就會(huì)調(diào)用上一個(gè)響應(yīng)者的touches方法

如何去尋找上一個(gè)響應(yīng)者?
1.如果當(dāng)前的View是控制器的View,那么控制器就是上一個(gè)響應(yīng)者.
2.如果當(dāng)前的View不是控制器的View,那么它的父控件就是上一個(gè)響應(yīng)者.
3.在視圖層次結(jié)構(gòu)的最頂級(jí)視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對(duì)象進(jìn)行處理
4.如果window對(duì)象也不處理,則其將事件或消息傳遞給UIApplication對(duì)象
5.如果UIApplication也不能處理該事件或消息,則將其丟棄
響應(yīng)者鏈條示意圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容