UI之事件與手勢(shì)

iOS中的事件可以分為三大類(lèi):

1> 觸摸事件

2> 加速計(jì)事件

3> 遠(yuǎn)程控制事件

響應(yīng)者對(duì)象

在iOS中不是任何對(duì)象都能處理事件,只有繼承了UIResponder的對(duì)象才能接收并處理事件.我們稱(chēng)之為"響應(yīng)者對(duì)象".

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

UIResponder

UIResponder內(nèi)部提供了方法來(lái)處理事件;

1> 觸摸事件

一次完成的觸摸過(guò)程,會(huì)經(jīng)歷3個(gè)狀態(tài);

UIView的觸摸事件處理

1、一根或多根手指開(kāi)始觸摸view,系統(tǒng)會(huì)自動(dòng)調(diào)用view下面的方法:

?

1

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;? //觸摸開(kāi)始

2、一根或者多根手指在view上移動(dòng),系統(tǒng)會(huì)自動(dòng)調(diào)用view下面的方法(隨著手指的移動(dòng),會(huì)持續(xù)調(diào)用該方法):

?

1

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;? //觸摸移動(dòng)

3、一根或者多根手指離開(kāi)view,系統(tǒng)會(huì)自動(dòng)調(diào)用view下面的方法:

?

1

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;? //觸摸結(jié)束

4、觸摸結(jié)束前,某個(gè)系統(tǒng)事件(例如電話(huà)呼入)會(huì)打斷觸摸過(guò)程,系統(tǒng)會(huì)自動(dòng)調(diào)用view下面的方法

?

1

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; //觸摸取消(可能會(huì)經(jīng)歷)

4個(gè)觸摸事件的處理方法中,都有 NSSet *touches 和 UIEvent *event 兩個(gè)參數(shù);

1、一次完整的觸摸過(guò)程,只會(huì)產(chǎn)生一個(gè)事件對(duì)象,4個(gè)觸摸方法都是同一個(gè)event參數(shù);

2、如果兩根手指同時(shí)觸摸一個(gè)view,那么view只會(huì)調(diào)用一次 touchesBegan:withEvent: 方法,touches參數(shù)中裝著兩個(gè)UITouch對(duì)象;

3、如果這兩根手指一前一后分開(kāi)觸摸同一個(gè)view,那么view會(huì)分別調(diào)用兩次 touchesBegan:withEvent:方法, 并且每次調(diào)用時(shí)的touches參數(shù)只包含一個(gè)UITouch對(duì)象;

4、根據(jù)touches中UITouch個(gè)數(shù)可以判斷出使單點(diǎn)觸摸還是多點(diǎn)觸摸。

提示:touches中存放的都是UITouch對(duì)象。

2> 加速計(jì)事件

?

1

2

3

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;

- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

3> 遠(yuǎn)程控制事件

?

1

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

UITouch

當(dāng)用戶(hù)用一根手指觸摸屏幕時(shí),會(huì)創(chuàng)建一個(gè)與手指相關(guān)聯(lián)的UITouch對(duì)象;一根手指對(duì)應(yīng)一個(gè)UITouch對(duì)象;

UITouch的作用:

保存跟手指相關(guān)的信息,比如觸摸的位置、時(shí)間、階段;

當(dāng)手指移動(dòng)時(shí),系統(tǒng)會(huì)更新同一個(gè)UITouch對(duì)象,使之能夠一直保存該手指的觸摸位置;

當(dāng)手指離開(kāi)屏幕時(shí),系統(tǒng)會(huì)銷(xiāo)毀相應(yīng)的UITouch對(duì)象。

提示:iPhone開(kāi)發(fā)中,要避免使用雙擊事件。

UITouch的屬性:

觸摸產(chǎn)生時(shí)所處的窗口

?

1

@property(nonatomic,readonly,retain) UIWindow *window;

觸摸產(chǎn)生時(shí)所處的視圖

?

1

@property(nonatomic,readonly,retain) UIView *view;

短時(shí)間內(nèi)點(diǎn)按屏幕的次數(shù),可以根據(jù)tapCount判斷單擊、雙擊或更多地點(diǎn)擊

?

1

@property(nonatomic,readonly) NSUInteger tapCount;

記錄了觸摸事件產(chǎn)生或變化時(shí)的時(shí)間,單位是秒

?

1

@property(nonatomic,readonly) NSTimeInterval timestamp;

當(dāng)前觸摸事件所處的狀態(tài)

?

1

2

3

4

5

6

7

8

@property(nonatomic,readonly) UITouchPhase phase;

/*

UITouchPhase是一個(gè)枚舉類(lèi)型,包含:

UITouchPhaseBegan(觸摸開(kāi)始)

UITouchPhaseMoved(接觸點(diǎn)移動(dòng))

UITouchPhaseStationary(接觸點(diǎn)無(wú)移動(dòng))

UITouchPhaseEnded(觸摸結(jié)束)

UITouchPhaseCancelled(觸摸取消)*/

UITouch的方法:

?

1

- (CGPoint)locationInView:(UIView *)view;

1> 返回值表示觸摸在view上的位置;

2> 這里返回的位置是針對(duì)view坐標(biāo)系的,(以view的左上角為原點(diǎn)(0,0));

3> 調(diào)用時(shí)傳入的view參數(shù)為nil 的話(huà),返回的是觸摸點(diǎn)在UIWindow的位置。

?

1

- (CGPoint)previousLocationInView:(UIView *)view;

該方法記錄了前一個(gè)觸摸點(diǎn)的位置;

UIEvent

每產(chǎn)生一個(gè)事件,就會(huì)產(chǎn)生一個(gè)UIEvent對(duì)象;

UIEvent:稱(chēng)為事件對(duì)象,記錄事件產(chǎn)生的時(shí)刻和類(lèi)型。

常見(jiàn)屬性:

1> 事件類(lèi)型

?

@property(nonatomic,readonly) UIEventType? type;

@property(nonatomic,readonly) UIEventSubtype? subtype;

/*

typedef

NS_ENUM(NSInteger, UIEventType) {

UIEventTypeTouches,

UIEventTypeMotion,

UIEventTypeRemoteControl,

};

typedef

NS_ENUM(NSInteger, UIEventSubtype) {

// available in iPhone OS 3.0

UIEventSubtypeNone? ? ? ? ? ? ? ? ? ? ? ? ? ? ? = 0,

// for UIEventTypeMotion, available in iPhone OS 3.0

UIEventSubtypeMotionShake? ? ? ? ? ? ? ? ? ? ? = 1,

// for UIEventTypeRemoteControl, available in iOS 4.0

UIEventSubtypeRemoteControlPlay? ? ? ? ? ? ? ? = 100,

UIEventSubtypeRemoteControlPause? ? ? ? ? ? ? ? = 101,

UIEventSubtypeRemoteControlStop? ? ? ? ? ? ? ? = 102,

UIEventSubtypeRemoteControlTogglePlayPause? ? ? = 103,

UIEventSubtypeRemoteControlNextTrack? ? ? ? ? ? = 104,

UIEventSubtypeRemoteControlPreviousTrack? ? ? ? = 105,

UIEventSubtypeRemoteControlBeginSeekingBackward = 106,

UIEventSubtypeRemoteControlEndSeekingBackward? = 107,

UIEventSubtypeRemoteControlBeginSeekingForward? = 108,

UIEventSubtypeRemoteControlEndSeekingForward? ? = 109,

};

*/

2> 事件產(chǎn)生的時(shí)間

?

1

@property(nonatomic,readonly) NSTimeInterval? timestamp;

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

觸摸事件的產(chǎn)生:

1> 發(fā)生觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中;

2> UIApplication會(huì)從事件隊(duì)列中取出最前面的事件,并將事件分發(fā)下去以便處理,通常,先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow);

3> 主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖控件來(lái)處理觸摸事件,這也是整個(gè)事件處理過(guò)程的第一步;

4> 找到合適的視圖控件后,就會(huì)調(diào)用視圖控件的touches方法來(lái)做具體的事件處理。

觸摸事件的傳遞:

觸摸事件的傳遞是從父控件傳遞到子控件;

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

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

1> 不接受用戶(hù)交互 :userInteractionEnable = NO;

2> 隱藏 :hidden = YES;

3> 透明:alpha = 0.0 ~ 0.01

提示:UIImageView的userInteractionEnable默認(rèn)就是NO,因此UIImageView以及它的子控件默認(rèn)是不能接收觸摸事件的。

觸摸事件處理的詳細(xì)過(guò)程:

用戶(hù)點(diǎn)擊屏幕后產(chǎn)生的一個(gè)觸摸事件,經(jīng)過(guò)一些列的傳遞過(guò)程后,會(huì)找到最合適的視圖控件來(lái)處理這個(gè)事件

找到最合適的視圖控件后,就會(huì)調(diào)用控件的touches方法來(lái)作具體的事件處理

touchesBegan…

touchesMoved…

touchedEnded…

這些touches方法的默認(rèn)做法是將事件順著響應(yīng)者鏈條向上傳遞,將事件交給上一個(gè)響應(yīng)者進(jìn)行處理

響應(yīng)者鏈的事件傳遞過(guò)程:

1> 如果view的控制器存在,就傳遞給控制器;如果控制器不存在,則將其傳遞給它的父視圖;

2> 在視圖層次結(jié)構(gòu)最頂級(jí)的視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對(duì)象進(jìn)行處理。

3> 如果window對(duì)象也不處理,則其將事件或消息傳遞給UIApplication對(duì)象;

4> 如果UIApplication也不能處理該事件或消息,則將其丟棄。

監(jiān)聽(tīng)觸摸事件的做法

如果想監(jiān)聽(tīng)一個(gè)view上面的觸摸事件,之前的做法是:

1> 自定義一個(gè)view;

2> 實(shí)現(xiàn)view的touches方法,在方法內(nèi)部實(shí)現(xiàn)具體處理代碼。

通過(guò)touches方法監(jiān)聽(tīng)view觸摸事件,有很明顯的幾個(gè)缺點(diǎn):

1> 必須得自定義view;

2> 由于是在view內(nèi)部的touches方法中監(jiān)聽(tīng)觸摸事件,因此默認(rèn)情況下,無(wú)法讓其他外界對(duì)象監(jiān)聽(tīng)view的觸摸事件;

3> 不容易區(qū)分用戶(hù)的具體手勢(shì)行為。

iOS 3.2之后,蘋(píng)果推出了手勢(shì)識(shí)別功能(Gesture Recognizer),在觸摸事件處理方面,大大簡(jiǎn)化了開(kāi)發(fā)者的開(kāi)發(fā)難度。

UIGestureRescognizer

為了完成手勢(shì)識(shí)別,必須借助于手勢(shì)識(shí)別器:UIGestureRecognizer 。

利用UIGestureRecognizer,能輕松識(shí)別用戶(hù)在某個(gè)view上面做的一些常見(jiàn)手勢(shì)。

UIGestureRecognizer是一個(gè)抽象類(lèi),定義了所有的手勢(shì)基本行為,使用它的子類(lèi)才能處理具體的手勢(shì)

?

UITapGestureRecognizer(敲擊)

UIPinchGestureRecognizer(捏合,用于縮放)

UIPanGestureRecognizer(拖拽)

UISwipeGestureRecognizer(輕掃)

UIRotationGestureRecognizer(旋轉(zhuǎn))

UILongPressGestureRecognizer(長(zhǎng)按)

每一個(gè)手勢(shì)識(shí)別器的用法都差不多,比如UITapGestureRecognizer的使用步驟如下:

1> 創(chuàng)建手勢(shì)識(shí)別器對(duì)象;

?


UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];

2> 設(shè)置手勢(shì)識(shí)別器對(duì)象的具體屬性;

?

// 連續(xù)敲擊2次

tap.numberOfTapsRequired = 2;

// 需要2根手指一起敲擊

tap.numberOfTouchesRequired = 2;

3> 添加手勢(shì)識(shí)別器到對(duì)應(yīng)的view上;

?

1

[self.iconView addGestureRecognizer:tap];

4> 監(jiān)聽(tīng)手勢(shì)的觸發(fā)

?

1

[tap addTarget:self action:@selector(tapIconView:)];

手勢(shì)識(shí)別的狀太

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {

// 沒(méi)有觸摸事件發(fā)生,所有手勢(shì)識(shí)別的默認(rèn)狀態(tài)

UIGestureRecognizerStatePossible,

// 一個(gè)手勢(shì)已經(jīng)開(kāi)始但尚未改變或者完成時(shí)

UIGestureRecognizerStateBegan,

// 手勢(shì)狀態(tài)改變

UIGestureRecognizerStateChanged,

// 手勢(shì)完成

UIGestureRecognizerStateEnded,

// 手勢(shì)取消,恢復(fù)至Possible狀態(tài)

UIGestureRecognizerStateCancelled,

// 手勢(shì)失敗,恢復(fù)至Possible狀態(tài)

UIGestureRecognizerStateFailed,

// 識(shí)別到手勢(shì)識(shí)別

UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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