iOSDay23之事件處理

1. 事件的基本概念

 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屬性

  transformview的一個重要屬性,他在矩陣層面上改變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 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章