iOS中的事件
1.事件的生命周期
事件的生命周期從事件的產(chǎn)生和傳遞(事件如何從父控件傳遞到子控件并尋找到最合適的view氛堕、尋找最合適的view的底層實現(xiàn)泪蔫、攔截事件的處理)->事件的響應(yīng)(找到最合適的view后對事件進行處理,touches方法的重寫)
2.事件的分類
iOS中的事件可以分為3大類型:
- 觸屏事件(例如點擊按鈕进每、通過手勢縮放圖片捐名、拖動上下滾動頁面等)
- 傳感器事件(例如搖一搖紅包辨萍、通過旋轉(zhuǎn)設(shè)備控制賽車方向烘跺、指南針等)
- 遠程控制事件(例如耳機的線控湘纵、外接手柄、遙控器等)
3.響應(yīng)者對象(UIResponder)
在iOS中只有繼承了UIResponder的對象才能接收和處理事件滤淳,UIResponder的子類包括UIView梧喷,UIViewController,UIApplication等。響應(yīng)者接收到原始事件數(shù)據(jù)铺敌,必須處理事件轉(zhuǎn)發(fā)到另一個響應(yīng)者對象绊困,當(dāng)APP接收到一個事件事,UIKit自動引導(dǎo)事件到最合適的的響應(yīng)者對象适刀,也叫做第一響應(yīng)者。
UIResponder內(nèi)部提供了以下方法來處理事件
觸摸事件
- (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;
4.事件中的概念
在自定義UIView為屬性的控件時可以重寫觸摸事件的方法來進行點擊回調(diào)煤蹭。在回調(diào)中可以看到方法接收兩個參數(shù)笔喉,一個是UITouch對象的集合,還有一個是UIEvent對象硝皂。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"觸摸開始--touches:%@,event:%@",touches,event);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"開始移動--touches:%@,event:%@",touches,event);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"觸摸結(jié)束--touches:%@,event:%@",touches,event);
}
//只有在程序強制退出或者來電時才會調(diào)用
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"觸摸取消--touches:%@,event:%@",touches,event);
}
4.1UIEvent
表示用戶交互的事件對象常挚,每產(chǎn)生一個事件,就會產(chǎn)生一個UIEvent對象稽物。在一個用戶點擊事件處理過程中奄毡,UIEvent對象是唯一的。
UIEvent屬性如下:
//事件類型
@property(nonatomic,readonly) UIEventType type NS_AVAILABLE_IOS(3_0);
@property(nonatomic,readonly) UIEventSubtype subtype NS_AVAILABLE_IOS(3_0);
//事件產(chǎn)生時間
@property(nonatomic,readonly) NSTimeInterval timestamp;
4.2UITouch
當(dāng)用戶用一根手指觸摸屏幕時贝或,會創(chuàng)建一個與手指相關(guān)的UITouch對象 吼过,一根手指對應(yīng)一個UITouch對象。
UITouch屬性如下:
//觸摸產(chǎn)生時所處的窗口
@property(nonatomic,readonly,retain) UIWindow *window;
//觸摸產(chǎn)生時所處的視圖
@property(nonatomic,readonly,retain) UIView *view
;
//短時間內(nèi)點按屏幕的次數(shù)咪奖,可以根據(jù)tapCount判斷單擊盗忱、雙擊或更多的點擊
@property(nonatomic,readonly) NSUInteger tapCount;
//記錄了觸摸事件產(chǎn)生或變化時的時間,單位是秒
@property(nonatomic,readonly) NSTimeInterval timestamp;
//當(dāng)前觸摸事件所處的狀態(tài)
@property(nonatomic,readonly) UITouchPhase phase;
UITouch方法如下:
// 返回值表示觸摸在view上的位置
// 這里返回的位置是針對view的坐標系的(以view的左上角為原點(0, 0))
// 調(diào)用時傳入的view參數(shù)為nil的話羊赵,返回的是觸摸點在UIWindow的位置
(CGPoint)locationInView:(UIView *)view;
// 該方法記錄了前一個觸摸點的位置
(CGPoint)previousLocationInView:(UIView *)view;
事件的傳遞和響應(yīng)
1.事件的產(chǎn)生和傳遞
1.1事件的產(chǎn)生
1.發(fā)生觸摸事件后趟佃,系統(tǒng)會將該事件加入到一個由UIApplication管理的隊列事件中
2.UIApplication會從事件隊列中取出最前面的事件,并將事件分發(fā)下去以便處理昧捷,通常會先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow)
3.主窗口會在視圖層次結(jié)構(gòu)中找到一個最合適的視圖來處理觸摸事件
1.2事件的傳遞
觸摸事件的傳遞是從父控件傳遞到子控件闲昭。事件傳遞給窗口或者控件后,就調(diào)用hitTest:withEvent:
方法尋找更合適的view靡挥。方法底層會調(diào)用pointInside:withEvent:
方法判斷點在不在方法調(diào)用者的坐標系上序矩,如果返回YES說明點在當(dāng)前view上,繼續(xù)通過hitTest:withEvent:
方法遍歷子控件芹血,直到找到最合適的view贮泞。如返回NO,代表事件不在view內(nèi)幔烛,直接返回nil啃擦,說明當(dāng)前view不是最合適的view,其以下的子控件也都會被忽略饿悬。
這個方法會忽略以下情況:
- 視圖是隱藏的 hidden = YES
- 用戶交互是關(guān)閉的 userInteractionEnabled = NO
- 透明度小于0.01的 alpha < 0.01
2.事件的響應(yīng)
- 響應(yīng)者鏈條
在ios程序中每個控件的擺放是有前后關(guān)系的令蛉,這種先后關(guān)系構(gòu)成的一個鏈條就叫響應(yīng)者鏈。 - 響應(yīng)者鏈的事件傳遞過程
1.如果當(dāng)前view是控制器的view,那么控制器就是上一個響應(yīng)者珠叔,事件就傳遞給控制器蝎宇;如果當(dāng)前view不是控制器的view,那么父視圖就是當(dāng)前view的上一個響應(yīng)者祷安,事件就傳遞給它的父視圖
2.在視圖層次結(jié)構(gòu)的最頂級視圖姥芥,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對象進行處理
3.如果window對象也不處理汇鞭,則其將事件或消息傳遞給UIApplication對象
4.如果UIApplication也不能處理該事件或消息凉唐,則將其丟棄