iOS手勢手勢操作詳解
iOS手勢手勢操作詳解
目錄
一、UIResponder
二、UIGestureRecognizer 手勢識別
三、響應鏈
**API原文**:Events are objects sent to an app to inform it of user actions. In iOS, events can take many forms: Multi-Touch events, motion events, and events for controlling multimedia. This last type of event is known as a remote control event because it can originate from an external accessory.
事件是發送給一個應用程序,通知用戶操作它的對象。在IOS中,事件可以采取多種形式:多點觸摸事件,移動事件,和控制多媒體事件。這最后一種類型的事件被稱為遠程控制事件,因為它可以源于外部附件。
一、UIResponder
在iOS中,只要繼承于UIResponder都能處理響應者事件,UIView繼承于UIResponder,而大多數空間最終都繼承于UIView。在3.2版本之前,iOS處理屏幕觸摸,主要由UIResponder來管理。
iOS中的事件大概分為三種:
1、觸摸事件
2、加速事件
3、遠程控制事件
1、觸摸事件
1.1 touchesBegan,當點觸摸,開始觸摸。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
1.2 touchesMoved,屏幕上移動。
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
1.3 touchesEnded,抬起手指。
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
1.4 touchesCancelled,電話呼入等中斷手勢的事件。
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
1.5 touchesEstimatedPropertiesUpdated,9.1之后加入的3D觸摸事件。
- (void)touchesEstimatedPropertiesUpdated:(NSSet * _Nonnull)touches NS_AVAILABLE_IOS(9_1);
2、加速事件
2.1 開始加速
- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
2.2 結束加速
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
2.3 加速中斷
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
3、遠程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
每個方法系統默認傳入兩個參數,一個是touches,是NSSet的類對象,一個是event,是UIEvent的類對象。先看看這兩個參數的含義吧。筆者大多數都是參考蘋果官方API得知的。
4、NSSet類和UITouch類。
4.1 NSSet。
4.1.1 無序性,存放到NSSet中的元素沒有順序。
代碼驗證:
NSSet *set1 = [NSSet setWithObjects:@(1), @"h", @"h", @(1), @"a", @"we", nil]; for (id obj in set1) { NSLog(@"%@", obj); }
控制臺輸出
2016-01-21 12:43:55.711 test[1662:901144] a 2016-01-21 12:43:55.711 test[1662:901144] we 2016-01-21 12:43:55.711 test[1662:901144] 1 2016-01-21 12:43:55.711 test[1662:901144] h Program ended with exit code: 0
結果可以看出存放的順序和打印輸出的順序無關,證明了無序性。
4.1.2 互異性。存放到NSSet中的元素互不相同。
代碼驗證:
NSSet *set = [NSSet setWithObjects:@(1), @(2), @"aa", @"aa", nil]; NSLog(@"%@", @(set.count));
控制臺輸出
2016-01-21 12:47:16.815 test[1702:918703] 3 Program ended with exit code: 0
一共輸入了4個對象,有一個重復對象,打印輸出個數為3個,證明了互異性。
無序性和互異性這兩點類似數學上的集合。
</div>
4.1.3 通過anyObject來訪問單個元素。
4.1.4 通過forin循環來遍歷NSSet中的每一個元素。
4.1.5 高效率。
4.2 UITouch。
4.2.1 UITouch簡單介紹
用戶用一根手指觸摸屏幕時,系統會自動創建一個與手指相關聯的UITouch對象,一根手指對應一個UITouch對象,系統會自動把這些UITouch對象存放到NSSet集合中,所以,有了上文中提到的手指移動方法中的參數touches
4.2.2 UITouch作用
保存手指觸摸屏幕的一些相關信息,如觸摸的位置、時間、階段,當手在指移動時,系統會自動更新這個手指最初觸摸屏幕創建的同一個UITouch對象,使得能夠一直保存該手指的觸摸信息。當手指離開屏幕時,系統會自動銷毀相應的UITouch對象。
4.2.3 UITouch的屬性
4.2.3.1 觸摸產生時所處的窗口。窗口可能發生變化,當前窗口不一定是最開始觸摸的窗口。
<pre>@property(nonatomic,readonly,retain) UIWindow *window;</pre>
4.2.3.2 觸摸產生時所處的視圖。視圖可能發生變化,當前視圖也不一定時最初的視圖。
<pre>@property(nonatomic,readonly,retain) UIView *view;</pre>
4.2.3.3 短時間內點按屏幕的次數,可以根據tapCount判斷單擊、雙擊或更多的點擊。
<pre>@property(nonatomic,readonly) NSUInteger tapCount;</pre>
4.2.3.4 記錄了觸摸事件產生或變化時的時間,單位是秒。
<p>@property(nonatomic,readonly) NSTimeInterval timestamp;</p>
4.2.3.5 當前觸摸事件在某一個周期中所處的狀態。
<pre>@property(nonatomic,readonly) UITouchPhase phase;</pre>
phase是UITouchPhase類型的,是一個枚舉,包含了:
typedef NS_ENUM(NSInteger, UITouchPhase) { UITouchPhaseBegan, // whenever a finger touches the surface. UITouchPhaseMoved, // whenever a finger moves on the surface. UITouchPhaseStationary, // whenever a finger is touching the surface but hasn't moved since the previous event. UITouchPhaseEnded, // whenever a finger leaves the surface. UITouchPhaseCancelled, // whenever a touch doesn't end but we need to stop tracking (e.g. putting device to face) };
- UITouchPhaseBegan(觸摸開始)
- UITouchPhaseMoved(接觸點移動)
- UITouchPhaseStationary(接觸點無移動)
- UITouchPhaseEnded(觸摸結束)
- UITouchPhaseCancelled(觸摸取消)
</ul>
4.2.4 UITouch的成員方法
- (CGPoint)locationInView:(nullable UIView *)view;
- 返回值表示觸摸在當前view上的位置,這里返回的位置是相對view的坐標(以view的左上角為原點(0, 0))
注意:調用時傳入的view參數為nil的話,返回的是觸摸點在UIWindow的位置。
- (CGPoint)previousLocationInView:(nullable UIView *)view;
- 該方法記錄了當前一個觸摸點的位置
-
5、 UIEvent
每當發生一個完整的觸摸事件,就會產生一個UIEvent對象,UIEvent,稱為事件對象,記錄事件發生的時刻和類型。
5.1 UIEvent常見屬性
事件類型
@property(nonatomic,readonly) UIEventType type NS_AVAILABLE_IOS(3_0);
@property(nonatomic,readonly) UIEventSubtype subtype NS_AVAILABLE_IOS(3_0);
時間產生的時間
@property(nonatomic,readonly) NSTimeInterval timestamp;
6、一次完整的觸摸
一般情況下一次完整的觸摸,會經歷3個狀態:
觸摸開始:- (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
- 4個觸摸事件中,都有NSSet touches和UIEvent event兩個參數,一次完整的觸摸過程中,只會產生一個事件對象,4個觸摸方法都是同一個event對象,也就是說四個方法的event都是同一個參數。
- 如果兩根手指同時觸摸一個view,那么view只會調用一次touchesBegan:withEvent:方法,touches參數中裝著2個UITouch對象。
- 如果這兩根手指一前一后分開觸摸同一個view,那么view會分別調用2次touchesBegan:withEvent:方法,并且每次調用時的touches參數中只包含一個UITouch對象
- 根據touches中UITouch的個數可以判斷出是單點觸摸還是多點觸摸