iOS事件機制,以及不同手勢使用touchesBegan等表現形式


事件處理方法

UIResponder中定義了一系列對事件的處理方法,他們分別是:

  • –(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

從方法名字可以知道,他們分別對應了屏幕事件的開始、移動、結束和取消幾個階段,前三個階段理解都沒問題,最后一個取消事件的觸發時機是在諸如突然來電話或是系統殺進程時調用。這些方法的第一個參數定義了UITouch對象的一個集合(NSSet),它的數量表示了這次事件是幾個手指的操作,目前iOS設備支持的多點操作手指數最多是5。第二個參數是當前的UIEvent對象。下圖展示了一個UIEvent對象與多個UITouch對象之間的關系。

一、點擊事件

首先,新建一個自定義的View繼承於UIView,並實現上述提到的事件處理方法,我們可以通過判斷UITouch的tapCount屬性來決定響應單擊、雙擊或是多次點擊事件。

MyView.m

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 
#import "MyView.h" @implementation MyView -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  for (UITouch *aTouch in touches) {  if (aTouch.tapCount == 2) {  // 處理雙擊事件  [self respondToDoubleTapGesture];  }  } } -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { } -(void)respondToDoubleTapGesture {  NSLog(@"respondToDoubleTapGesture"); } @end 

二、滑動事件

滑動事件一般包括上下滑動和左右滑動,判斷是否是一次成功的滑動事件需要考慮一些問題,比如大部分情況下,用戶進行一次滑動操作,這次滑動是否是在一條直線上?或者是否是基本能保持一條直線的滑動軌跡。或者判斷是上下滑動還是左右滑動等。另外,滑動手勢一般有一個起點和一個終點,期間是在屏幕上畫出的一個軌跡,所以需要對這兩個點進行判斷。我們修改上述的MyView.m的代碼來實現一次左右滑動的事件響應操作。

MyView.m

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 
#import "MyView.h" #define HORIZ_SWIPE_DRAG_MIN 12 //水平滑動最小間距 #define VERT_SWIPE_DRAG_MAX 4 //垂直方向最大偏移量 @implementation MyView -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {  UITouch *aTouch = [touches anyObject];  // startTouchPosition是一個CGPoint類型的屬性,用來存儲當前touch事件的位置  self.startTouchPosition = [aTouch locationInView:self]; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  UITouch *aTouch = [touches anyObject];  CGPoint currentTouchPosition = [aTouch locationInView:self];  // 判斷水平滑動的距離是否達到了設置的最小距離,並且是否是在接近直線的路線上滑動(y軸偏移量)  if (fabsf(self.startTouchPosition.x - currentTouchPosition.x) >= HORIZ_SWIPE_DRAG_MIN &&  fabsf(self.startTouchPosition.y - currentTouchPosition.y) <= VERT_SWIPE_DRAG_MAX)  {  // 滿足if條件則認為是一次成功的滑動事件,根據x坐標變化判斷是左滑還是右滑  if (self.startTouchPosition.x < currentTouchPosition.x) {  [self rightSwipe];//右滑響應方法  } else {  [self leftSwipe];//左滑響應方法  }  //重置開始點坐標值  self.startTouchPosition = CGPointZero;  } } -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {  //當事件因某些原因取消時,重置開始點坐標值  self.startTouchPosition = CGPointZero; } -(void)rightSwipe {  NSLog(@"rightSwipe"); } -(void)leftSwipe {  NSLog(@"leftSwipe"); } @end 

三、拖拽事件

在屏幕上我們可以拖動某一個控件(View)進行移動,這種事件成為拖拽事件,其實現原理就是在不改變View的大小尺寸的前提下改變View的顯示坐標值,為了達到動態移動的效果,我們可以在move階段的方法中進行坐標值的動態更改,還是重寫MyView.m的事件處理方法,這次在touchesMove方法中進行處理。

MyView.m

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 
#import "MyView.h" @implementation MyView -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {  UITouch *aTouch = [touches anyObject];  //獲取當前觸摸操作的位置坐標  CGPoint loc = [aTouch locationInView:self];  //獲取上一個觸摸點的位置坐標  CGPoint prevloc = [aTouch previousLocationInView:self];  CGRect myFrame = self.frame;  //改變View的x、y坐標值  float deltaX = loc.x - prevloc.x;  float deltaY = loc.y - prevloc.y;  myFrame.origin.x += deltaX;  myFrame.origin.y += deltaY;  //重新設置View的顯示位置  [self setFrame:myFrame]; } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { } @end 

四、雙指縮放

之前提到過UIEvent包含了一系列的UITouch對象構成一次事件,當設計多點觸控操作時,可與對UIEvent對象內的UITouch對象進行處理,比如實現一個雙指縮放的功能。

MyView.m

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 
#import "MyView.h" @implementation MyView {  BOOL pinchZoom;  CGFloat previousDistance;  CGFloat zoomFactor; } -(id)init {  self = [super init];  if (self) {  pinchZoom = NO;  //縮放前兩個觸摸點間的距離  previousDistance = 0.0f;  zoomFactor = 1.0f;  }  return self; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {  if(event.allTouches.count == 2) {  pinchZoom = YES;  NSArray *touches = [event.allTouches allObjects];  //接收兩個手指的觸摸操作  CGPoint pointOne = [[touches objectAtIndex:0] locationInView:self];  CGPoint pointTwo = [[touches objectAtIndex:1] locationInView:self];  //計算出縮放前后兩個手指間的距離絕對值(勾股定理)  previousDistance = sqrt(pow(pointOne.x - pointTwo.x, 2.0f) +  pow(pointOne.y - pointTwo.y, 2.0f));  } else {  pinchZoom = NO;  } } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {  if(YES == pinchZoom && event.allTouches.count == 2) {  NSArray *touches = [event.allTouches allObjects];  CGPoint pointOne = [[touches objectAtIndex:0] locationInView:self];  CGPoint pointTwo = [[touches objectAtIndex:1] locationInView:self];  //兩個手指移動過程中,兩點之間距離  CGFloat distance = sqrt(pow(pointOne.x - pointTwo.x, 2.0f) +  pow(pointOne.y - pointTwo.y, 2.0f));  //換算出縮放比例  zoomFactor += (distance - previousDistance) / previousDistance;  zoomFactor = fabs(zoomFactor);  previousDistance = distance;  //縮放  self.layer.transform = CATransform3DMakeScale(zoomFactor, zoomFactor, 1.0f);  } } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  if(event.allTouches.count != 2) {  pinchZoom = NO;  previousDistance = 0.0f;  } } -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { } @end 轉自:http://www.cnblogs.com/zhw511006/p/3517249.html 

上面實現的方式有一點不足之處就是必須兩個手指同時觸摸按下才能達到縮放的效果,並不能達到相冊里面那樣一個手指觸摸后,另一個手指按下也可以縮放。如果需要達到和相冊照片縮放的效果,需要同時控制begin、move、end幾個階段的事件處理。這個不足就留給感興趣的同學自己去實現了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM