1> 概述
事件是當用戶手指觸擊屏幕及在屏幕上移動時,系統不斷髮送給應用程序的對象。
系統將事件按照特定的路徑傳遞給可以對其進行處理的對象
在iOS中,一個UITouch對象表示一個觸摸,一個UIEvent對象表示一個事件。事件對象中包含與當前多點觸摸序列相對應的所有觸摸對象,還可以提供與特定視圖或窗口相關聯的觸摸對象。
2> 事件類型
2. 觸摸的基本概念
1> 概述
觸摸信息有時間和空間兩方面。
時間方面的信息稱爲階段(phrase),表示觸摸是否剛剛開始、是否正在移動或處處於靜止狀態,以及何時結束—--也就是手指何時從屏幕擡起。
空間方面是指當前在視圖或窗口中的位置信息,以及之前的位置信息(如果有的話)。當一個手指接觸屏幕時, 觸摸就和某個窗口或視圖關聯在一起,這個關聯在事件的整個生命週期都會得到維護。
2> 觸摸事件的階段
3> 觸摸事件的處理方法
在給定的觸摸階段中,如果發生新的觸摸動作或已有的觸摸動作發生變化,應用程序就會發送這些消息:
當一個或多個手指觸碰屏幕時,發送touchesBegan:withEvent:消息。
1 // 觸摸開始 2 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"觸摸TouchView開始"); 5 }
當一個或多個手指在屏幕上移動時,發送touchesMoved:withEvent:消息。
1 // 移動 2 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"移動TouchView"); 5 6 // 1.獲取觸摸手勢 7 UITouch *touch = [touches anyObject]; 8 9 // 2.獲取觸摸的位置 10 // locationInView: 獲取一個觸摸在某個視圖上的位置 11 CGPoint currentPoint = [touch locationInView:self.superview]; 12 13 // 3.根據觸摸的位置改變視圖的位置 14 self.center = currentPoint; 15 16 }
當一個或多個手指離開屏幕時,發送touchesEnded:withEvent:消息。
1 // 觸摸結束 2 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"觸摸TouchView結束"); 5 }
當觸摸被打斷時,發送touchesCancelled:withEvent:消息
1 // 觸摸被打斷 2 - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"觸摸TouchView被打斷"); 5 }
3. 響應者鏈
1> 概述
響應者鏈是一個響應者對象的連接序列,事件或動作消息(或菜單編輯消息)依次傳遞。
它允許響應者對象把事件處理的職責轉交給其它更高層的對象。
應用程序通過向上傳遞一個事件來查找合適的處理對象。因爲點擊檢測視圖也是一個響應者對象,應用程序在處理觸摸事件時也可以利用響應鏈。
由多個響應者對象組成的鏈。
2> 響應者
iOS中所有能響應事件(觸摸、晃動、遠程事件)的對象都是響應者。
系統定義了一個抽象的父類UIResponder來表示響應者。其子類都是響應者。
3> 檢測視圖
硬件檢測到觸摸操作,會將信息交給UIApplication,開始檢測。
順序(從最下層開始向上):UIApplication -> window -> viewController -> view -> 檢測所有視圖
最終確認觸碰位置,完成響應者鏈的查詢過程。
4> 處理觸摸事件
檢測到響應者後,實現touchesBegan:withEvent:等方法,即處理事件。
如果響應者沒有處理事件,事件會向下傳遞。如果沒有響應者處理,則丟棄觸摸事件。
事件處理的順序與觸摸檢測查詢相反。
觸摸的子視圖 -> view -> viewController -> window -> UIApplication
5> 阻斷響應者鏈
響應者鏈可以被打斷,無法完成檢測查詢過程。
視圖類的屬性 : userInteractionEnabled,關閉後能阻斷查詢過程,即值爲NO時,從當前視圖開始到所有的子視圖不再檢測。
6> 響應者鏈處理原則
-
點擊檢測視圖或者第一響應者傳遞事件或動作消息給它的視圖控制器(如果它有的話);如果沒有一個視圖控制器,就傳遞給它的父視圖。
-
如果一個視圖或者它的視圖控制器不能處理這個事件或動作消息,它將傳遞給該視圖的父視圖。
-
在這個視圖層次中的每個後續的父視圖遵循上述的模式。
-
最頂層的視圖如果不能處理這個事件或動作消息,就傳遞給UIWindow對象來處理。
-
如果UIWindow對象不能處理,就傳給單件應用程序對象UIApplication,如果應用程序對象也不能處理這個事件或動作消息,將拋棄它。
4. 手勢
1> 概述
手勢識別器是對觸摸事件做了封裝,手勢識別器本身起到了識別作用
手勢識別器是iOS中比較抽象的一個類,用於識別一個手勢,所謂手勢:有規律的觸摸。
2> 手勢分類
3> 手勢識別器
系統提供的手勢識別器這個抽象父類我們是不會直接使用的,而是根據需求使用特定的手勢識別器創建對象,系統所提供的手勢類型如下所示:(需要將下面的方法在viewDidLoad方法中調用才能實現)
① UITapGestureRecognizer是輕拍手勢識別器,能識別輕拍操作
1 // 創建一個輕拍手勢方法 2 - (void)tapGesture 3 { 4 // 1.創建手勢識別器對象 5 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction:)]; 6 7 // 2.將手勢添加到相應的視圖上 8 [self.rootView.myImageView addGestureRecognizer:tap]; 9 } 10 11 // 實現輕拍手勢事件 12 - (void)tapGestureAction:(UITapGestureRecognizer *)tap 13 { 14 NSLog(@"被拍了!"); 15 }
② UIPanGestureRecognizer是平移手勢識別器,能識別拖拽操作
1 // 創建一個平移手勢方法 2 - (void)panGesture 3 { 4 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAction:)]; 5 6 [self.rootView.myImageView addGestureRecognizer:pan]; 7 } 8 9 // 實現平移手勢事件 10 - (void)panGestureAction:(UIPanGestureRecognizer *)pan 11 { 12 NSLog(@"我動了..."); 13 14 // 在View上面挪動的距離,translationInView是用來獲取觸摸移動的距離 15 CGPoint p = [pan translationInView:pan.view]; 16 17 pan.view.transform = CGAffineTransformTranslate(pan.view.transform, p.x, p.y); // pan.view.transform 表示視圖原來的位置,p.x表示移動的X軸方向的距離,p.y表示移動的Y軸方向的距離 18 19 // 清空移動的距離 20 [pan setTranslation:CGPointZero inView:pan.view];
③ UIPinchGestureRecognizer是捏合手勢識別器,能識別捏合操作
1 - (void)pinchGesture 2 { 3 UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureAction:)]; 4 [self.rootView.myImageView addGestureRecognizer:pinch]; 5 } 6 7 // 實現捏合方法 8 - (void)pinchGestureAction:(UIPinchGestureRecognizer *)pinch 9 { 10 pinch.view.transform = CGAffineTransformScale(pinch.view.transform, pinch.scale, pinch.scale); 11 pinch.scale = 1; // 清空移動的比例 12 }
④ UIRotationGestureRecognizer是旋轉手勢識別器,能識別旋轉操作
1 // 創建一個旋轉手勢方法 2 - (void)rotattionGesture 3 { 4 UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotattionGestureAction:)]; 5 6 [self.rootView addGestureRecognizer:rotation]; 7 } 8 9 // 實現旋轉手勢事件 10 - (void)rotattionGestureAction:(UIRotationGestureRecognizer *)rotation 11 { 12 rotation.view.transform = CGAffineTransformRotate(rotation.view.transform, rotation.rotation); // rotation的旋轉角度是rotation屬性 13 rotation.rotation = 0; 14 }
⑤ UILongPressGestureRecognizer是長按手勢識別器,能識別長按操作
1 // 創建一個長按手勢方法 2 - (void)longPress 3 { 4 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)]; 5 [self.rootView.myImageView addGestureRecognizer:longPress]; 6 } 7 8 // 實現長按手勢事件 9 - (void)longPressAction:(UILongPressGestureRecognizer *)longPress 10 { 11 if (longPress.state == UIGestureRecognizerStateBegan) { 12 // 設置長按的時間 13 longPress.minimumPressDuration = 2; 14 NSLog(@"長按了..."); 15 } 16 }
⑥ UISwipeGestureRecognizer是輕掃手勢識別器,能識別拖拽操作
1 // 創建一個輕掃手勢方法 2 - (void)swipe 3 { 4 UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeAction:)]; 5 6 // 設置輕掃的有效方向 7 swipe.direction = UISwipeGestureRecognizerDirectionLeft; // 默認爲Right(右) 8 9 // 手指的數量 10 // swipe.numberOfTouchesRequired = 2; // 默認爲1 11 12 [self.rootView.myImageView addGestureRecognizer:swipe]; 13 } 14 15 // 實現輕掃手勢事件 16 - (void)swipeAction:(UISwipeGestureRecognizer *)swipe 17 { 18 NSLog(@"向左掃了一下!"); 19 }
⑦ UIScreenEdgePanGestureRecognizer是屏幕邊緣輕掃識別器
1 // 創建一個屏幕邊緣清掃方法 2 - (void)screenEdgePan 3 { 4 UIScreenEdgePanGestureRecognizer *screenEdgePan = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(screenEdgePanAction:)]; 5 6 screenEdgePan.edges = UIRectEdgeLeft; // 所有的 7 8 [self.rootView addGestureRecognizer:screenEdgePan]; 9 } 10 // 實現屏幕邊緣清掃事件 11 - (void)screenEdgePanAction:(UIScreenEdgePanGestureRecognizer *)screenEdgePan 12 { 13 NSLog(@"屏幕左邊緣清掃"); 14 }
4> 手勢識別器使用步驟小結
- 創建UIxxxGestureRecognizer對象,使用initWithTarget:action:方法
-
配置要識別的手勢相關信息
-
將手勢添加到某個視圖上
-
實現手勢識別器裏定義的方法
5> View的transform屬性
transform是view的一個重要屬性,他在矩陣層面上改變view的顯示狀態,能實現view的縮放 , 旋轉 , 平移等功能
平移 CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty) t --- 表示視圖原來的位置, tx --- 移動的X軸方向的距離, ty --- 移動的Y軸方向的距離
具體使用方法見 3> ② 的代碼
縮放 CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy) t --- 表示視圖原來的位置, tx --- 縮放的X軸方向的比例, ty --- 縮放的Y軸方向的比例 具體使用方法見 3> ③ 的代碼
旋轉 CGAffineTransformRotate(CGAffineTransform t, CGFloat angle) t --- 表示視圖原來的位置 , angle --- 表示旋轉角度 具體使用方法見 3> ④ 的代碼
6> 通過代理實現同時識別多個手勢
① 在需要的多個手勢中設置代理
xxx.delegate = self;
② 遵循協議 UIGestureRecognizerDelegate
③ 實現代理方法來實現同時識別多個手勢
1 #pragma mark 通過代理實現同時識別多個手勢 2 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 3 { 4 return YES; 5 }