天天看點

iphone的手勢與觸摸程式設計學習筆記

一、基本概念與了解:

Cocoa Touch将觸摸事件發送到正在處理的視圖。觸摸傳達的資訊包括:

  • 觸摸發生的位置 (目前位置、最近的曆史位置)
  • 觸摸的階段 (按下、移動、彈起) 
  • 輕擊數量 (tapCount 單擊/輕按兩下) 
  • 觸摸發生時間 (時間戳)  

每個UITouch對象都代表一個觸摸事件。在iPhone中,觸摸互動遵循一種原始的設計模式,即在UIView類中而非UIViewController類中程式設計實作。就是說觸摸互動采用視圖級程式設計方式。  

如何觸摸的,即所謂的基本手勢,包括:

  • Swipe:滑過,快速移動
  • Pinch Open:二指往外撥動
  • Pinch Close:二指往内撥動
  • Tap:輕擊
  • Touch and hold:長按

這些手勢的具體實作最原始的(相對最新的iOS版本)就是通過4個視圖方法自定義程式設計來實作。

二、 觸摸和視圖方法——自定義手勢程式設計

       預定義的4個回調方法就是處理螢幕上觸摸的開始、移動和結束。

       當使用者開始觸摸螢幕時,在事件的開始階段被調用——touchesBegan: withEvent:

       處理手指的移動——touchesMoved: withEvent:

       當手指離開螢幕時,結束觸摸過程——touchesEnded: withEvent:

       必須響應持續觸摸事件的系統中斷時調用——touchesCancelled: withEvent:

這4個方法都是一種UIResponder方法,通常在UIView子類中實作。所有視圖繼承了這些方法的基本版本。示例:自定義一個Tickle(類似劃卡)手勢。

//  TickleGestureRecognizer.h
//

#import <UIKit/UIKit.h>

typedef enum {
    DirectionUnknown = 0,
    DirectionLeft,
    DirectionRight
} Direction;

@interface TickleGestureRecognizer : UIGestureRecognizer

@property (assign) int tickleCount;
@property (assign) CGPoint curTickleStart;
@property (assign) Direction lastDirection;

@end      
//
//  TickleGestureRecognizer.m
//

#import "TickleGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>

#define REQUIRED_TICKLES 2
#define MOVE_AMT_PER_TICKLE 25

@implementation TickleGestureRecognizer
@synthesize tickleCount;
@synthesize curTickleStart;
@synthesize lastDirection;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    self.curTickleStart = [touch locationInView:self.view];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint ticklePoint = [touch locationInView:self.view];
    CGFloat moveAmt = ticklePoint.x - curTickleStart.x;
    Direction curDirection;
    if (moveAmt < 0) {
        curDirection = DirectionLeft;
    }else{
        curDirection = DirectionRight;
    }
    if (ABS(moveAmt) < MOVE_AMT_PER_TICKLE) return;
    
    // Make sure we've switched directions
    if (self.lastDirection == DirectionUnknown || (self.lastDirection == DirectionLeft && curDirection == DirectionRight) || (self.lastDirection == DirectionRight && curDirection == DirectionRight)) {
        
        self.tickleCount++;
        self.curTickleStart = ticklePoint;
        self.lastDirection = curDirection;
        
        if (self.state == UIGestureRecognizerStatePossible && self.tickleCount > REQUIRED_TICKLES) {
            [self setState:UIGestureRecognizerStateEnded];
        }
    }
}

- (void)reset {
    self.tickleCount = 0;
    self.curTickleStart = CGPointZero;
    self.lastDirection = DirectionUnknown;
    if (self.state == UIGestureRecognizerStatePossible) {
        [self setState:UIGestureRecognizerStateFailed];
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self reset];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self reset];
}

@end      

其中方法locationInView:即擷取目前Touch點位置。若是擷取觸摸動作之前的位置則用previousLocationInView:方法。以上定義了一個TickleGestureRecognizer新類實作了Tickle手勢。具體使用則是:

// 要用手勢的UIView的控制器頭檔案中添加
- (void)handleTickle:(TickleGestureRecognizer *)recognizer;

// 要用手勢的UIView的控制器實作檔案
// viewDidLoad添加
TickleGestureRecognizer *recognizer = [[TickleGestureRecognizer alloc] initWithTarget:self action:@selector(handleTickle:)];
        recognizer.delegate = self; // 又見強大的委托
        [view addGestureRecognizer:recognizer]; // 用addGestureRecognizer方法将手勢添加到視圖上


// 委托的回調方法
- (void)handleTickle:(TickleGestureRecognizer *)recognizer {
    // Code.....
}      

三、利用UIGestureRecognizer類給視圖添加手勢

       iOS3.0後引入了UIGestueRecognizer類幫助我們處理觸摸動作下各種手勢的添加實作。要點就是在要添加手勢的視圖的控制器類必須實作UIGestureRecognizerDelegate委托協定。其實從編碼角度看,就是蘋果公司将所有的基本手勢由UIGestureRecognizer類來定義實作了(與自定義程式設計中的TickleGestureRecognizer異曲同工)并引入的委托機制。

四、iOS5.0中可以在StoryBoard Editor中可視化添加手勢