UIGestureRecognizer

iOS 手勢操作: 拖動墓拜,捏合港柜,旋轉(zhuǎn),點(diǎn)按咳榜,長按夏醉,輕掃,自定義

UIGestureRecognizer 介紹

手勢識別在iOS中非常重要涌韩,它極大地提高了移動設(shè)備的使用便捷性畔柔。

iOS系統(tǒng)在3.2 以后,提供了一些常用的手勢(UIGestureRecognizer的子類)臣樱,開發(fā)者可以直接使用它們進(jìn)行手勢操作靶擦。

* UIPanGestureRecognizer --- 拖動

* UIPinchGestureRecognizer ?--- 捏合

* UIRotationGestureRecognizer --- 旋轉(zhuǎn)

* UITapGestureRecognizer --- 點(diǎn)按

* UILongPassGestureRecognizer --- 長按

* UISwipeGestuerRecognizer --- 輕掃

另外腮考,可以通過繼承 UIGestureRecognizer 類,實(shí)現(xiàn)自定義手勢(手勢識別器類).

ps: 自定義手勢時(shí)玄捕,需要 #import <UIKit/UIGestureRecognizerSubclass.h>, 一般需要實(shí)現(xiàn)以下方法:

- (void)reset;

- (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;

//以上方法在分類 UIGestureRecognizer (UIGestureRecognizerProtected) 中聲明秸仙,更多方法聲明請自行查看

UIGestureRecognizer 的繼承關(guān)系如下:


手勢狀態(tài)

在六種手勢識別中,只有一種手勢是離散型手勢桩盲,它就是UITapGestureRecognizer

離散型手勢的特點(diǎn)是: 一旦識別就無法取消,而且只會調(diào)用一次手勢操作事件(初始化手勢時(shí)指定的回調(diào)方法)席吴。

換句話說其它五種手勢是連續(xù)型手勢赌结,而連續(xù)型手勢的特點(diǎn)就是: 會多次調(diào)用手勢事件操作事件,而且在連續(xù)手勢識別后可以取消手勢孝冒。從下圖可以看出兩者調(diào)用操作事件的次數(shù)是不同的:


手勢狀態(tài)枚舉如下:

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {

UIGestureRecognizerStatePossible,? // 尚未識別是何種手勢操作(但可能已經(jīng)觸發(fā)了觸摸事件)柬姚,默認(rèn)狀態(tài)

UIGestureRecognizerStateBegan,? ? ? // 手勢已經(jīng)開始,此時(shí)已經(jīng)被識別庄涡,但是這個(gè)過程中可能發(fā)生變化量承,手勢操作尚未完成

UIGestureRecognizerStateChanged,? ? // 手勢狀態(tài)發(fā)生轉(zhuǎn)變

UIGestureRecognizerStateEnded,? ? ? // 手勢識別操作完成(此時(shí)已經(jīng)松開手指)

UIGestureRecognizerStateCancelled,? // 手勢被取消,恢復(fù)到默認(rèn)狀態(tài)

UIGestureRecognizerStateFailed,? ? // 手勢識別失敗穴店,恢復(fù)到默認(rèn)狀態(tài)

UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // 手勢識別完成撕捍,同UIGestureRecognizerStateEnded

};

* 對于離散型手勢 UITapGestureRecognizer 要么被識別晰骑,要么失敗叶圃,點(diǎn)按(假設(shè)點(diǎn)按次數(shù)設(shè)置為1,并且沒有添加長按手勢)下去一次不松開則此時(shí)什么也不會發(fā)生融痛,松開手指立即識別并調(diào)用操作事件球凰,并且狀態(tài)為3(已完成)

* 但是連續(xù)型手勢要復(fù)雜一些狮腿,就拿旋轉(zhuǎn)手勢來說,如果兩個(gè)手指點(diǎn)下去不做任何操作呕诉,此時(shí)并不能識別手勢(因?yàn)槲覀冞€沒旋轉(zhuǎn))但是其實(shí)已經(jīng)出發(fā)了觸摸開始事件缘厢,此時(shí)狀態(tài)0;如果此時(shí)旋轉(zhuǎn)會被識別甩挫,也就會調(diào)用對應(yīng)的操作事件贴硫,同時(shí)狀態(tài)變成1(手勢開始),但是狀態(tài)1只有一瞬間伊者;緊接著狀態(tài)變成2(因?yàn)槲覀兊男D(zhuǎn)需要持續(xù)一會)夜畴,并且重復(fù)調(diào)用操作事件(如果在事件中打印狀態(tài)會重復(fù)打印2);松開手指删壮,此時(shí)狀態(tài)變成3贪绘,并調(diào)用1次操作事件。

使用手勢的步驟

使用手勢很簡單央碟,分為三步:

1. 創(chuàng)建手勢識別器對象實(shí)例税灌。創(chuàng)建時(shí)均函,指定一個(gè)回調(diào)方法,當(dāng)手勢開始菱涤,改變苞也、或結(jié)束時(shí),執(zhí)行回調(diào)方法粘秆。

2. 設(shè)置手勢識別器對象實(shí)例的相關(guān)屬性(可選部分)

3. 添加到需要識別的Veiw 中如迟。 每一個(gè)手勢只對應(yīng)一個(gè)View,當(dāng)屏幕觸摸到在View的邊界內(nèi)時(shí)攻走,如果手勢和預(yù)定的一樣殷勘,那就會執(zhí)行回調(diào)方法。

ps: 一個(gè)手勢只能對應(yīng)一個(gè)View昔搂,但是一個(gè)View 可以有多個(gè)手勢玲销。建議在真機(jī)上測試這些手勢,模擬器操作不太方便摘符,可能導(dǎo)致認(rèn)為手勢失效的情況贤斜。(模擬器測試捏合和旋轉(zhuǎn)手勢時(shí),按住option鍵逛裤,再用觸摸板或者鼠標(biāo)操作)

舉例說明(手勢所用的只)

功能描述:

附加到兩個(gè)圖片視圖 UIImageView 的有 ?"拖動"瘩绒、 "捏合"、 ?“旋轉(zhuǎn)”带族、“點(diǎn)按”草讶。

而“輕掃” 和 “自定義手勢 ?KMGestureRedcognizer” 附加在根視圖 UIView中。

1. 拖動: 進(jìn)行當(dāng)前圖片視圖位置移動


2.捏合: 進(jìn)行當(dāng)前圖片視圖縮放

3.旋轉(zhuǎn): 進(jìn)行當(dāng)前圖片視圖角度旋轉(zhuǎn)

4.點(diǎn)按: 雙擊恢復(fù)當(dāng)前圖片視圖的縮放炉菲,角度旋轉(zhuǎn)堕战,不透明度

5.長按: 設(shè)置當(dāng)前圖片視圖的 不透明度為0.7

6.輕掃: 左右輕掃設(shè)置兩個(gè)圖片視圖為居中,同時(shí)以垂直居中的特定偏移量定位

7.自定義手勢: 撓癢功能拍霜,左右輕掃共3次或以上嘱丢,設(shè)置兩個(gè)圖片視圖為居中,同時(shí)以水平居中的特定偏移量定位

效果如下:


/**

UI? ? ? UIGestureRecognizer 手勢練習(xí)

@param void <#void description#>

@return <#return value description#>

*/

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

// 為 自定義UI添加手勢

[self layoutUI];

// Do any additional setup after loading the view, typically from a nib.

}

#pragma mark - 自定義UI 并添加手勢

- (void)layoutUI

{

// 圖片視圖? _imgV

UIImage *img = [UIImage imageNamed:@"Tabbar_Discover_Normal"];

CGFloat cornerRadius = img.size.width;

_imgV = [[UIImageView alloc]initWithImage:img];

_imgV.frame = CGRectMake(20.0, 20.0, cornerRadius * 2, cornerRadius * 2);

_imgV.userInteractionEnabled = YES;

_imgV.layer.masksToBounds = YES;

_imgV.layer.cornerRadius = cornerRadius;

_imgV.layer.borderWidth = 2.0;

_imgV.layer.borderColor = [UIColor grayColor].CGColor;

[self.view addSubview:_imgV];

// 圖片視圖 _imgV2

img = [UIImage imageNamed:@"Tabbar_Feed_Normal"];

cornerRadius = img.size.width;

_imgV2 = [[UIImageView alloc]initWithImage:img];

_imgV2.frame = CGRectMake(20.0, 40.0 + _imgV.frame.size.height, cornerRadius * 2, cornerRadius * 2);

_imgV2.userInteractionEnabled = YES;

_imgV2.layer.masksToBounds = YES;

_imgV2.layer.cornerRadius = cornerRadius;

_imgV2.layer.borderWidth = 2.0;

_imgV2.layer.borderColor = [UIColor grayColor].CGColor;

[self.view addSubview:_imgV2];

/**

為創(chuàng)建的視圖 分別添加手勢

*/

// 添加 拖動手勢

[self bindPan:_imgV];

[self bindPan:_imgV2];

// 添加 捏合手勢

[self bindPinch:_imgV];

[self bindPinch:_imgV2];

// 添加 旋轉(zhuǎn)手勢

[self bindRotation:_imgV];

[self bindLongPress:_imgV2];

// 添加 點(diǎn)按手勢

[self bindTap:_imgV];

[self bindTap:_imgV2];

// 添加 長按手勢

[self bindLongPress:_imgV];

[self bindLongPress:_imgV2];

// 添加 輕掃手勢

[self bindSwipe];

[self bindSwipe];

}

#pragma mark - 綁定手勢操作

/**

綁定拖動手勢

@param imgVCustom 綁定到圖片視圖對象實(shí)例

*/

- (void)bindPan:(UIImageView *)imgVCustom{

UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePan:)];

[imgVCustom addGestureRecognizer:recognizer];

}

/**

綁定捏合手勢

@param imgVCustom 綁定到圖片視圖對象實(shí)例

*/

- (void)bindPinch:(UIImageView *)imgVCustom{

UIPinchGestureRecognizer *recognizer = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];

[imgVCustom addGestureRecognizer:recognizer];

}

/**

綁定旋轉(zhuǎn)手勢

@param imgVCustom 綁定到圖片視圖對象實(shí)例

*/

- (void)bindRotation:(UIImageView *)imgVCustom{

UIRotationGestureRecognizer *recognizer = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(handleRotation:)];

[imgVCustom addGestureRecognizer:recognizer];

}

- (void)bindTap:(UIImageView *)imgVCustom{

UITapGestureRecognizer *recognizewr = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];

// 使用一根手指雙擊時(shí)祠饺,才觸發(fā)點(diǎn)按手勢識別器

recognizewr.numberOfTapsRequired = 2;

recognizewr.numberOfTouchesRequired = 1;

[imgVCustom addGestureRecognizer:recognizewr];

}

- (void)bindLongPress:(UIImageView *)imgVCustom{

UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPress:)];

recognizer.minimumPressDuration? = 0.5; // 設(shè)置最小長按時(shí)間越驻; 默認(rèn)為0.5;

[imgVCustom addGestureRecognizer:recognizer];

}

- (void)bindSwipe{

// 向右輕掃手勢

UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipe:)];

recognizer.direction? = UISwipeGestureRecognizerDirectionRight; // 設(shè)置輕掃方向;

[self.view addGestureRecognizer:recognizer];

}

#pragma mark - 處理手勢操作

/**

處理拖動手勢

@param recognizer 拖動手勢識別器對象實(shí)例

*/

- (void)handlePan:(UIPanGestureRecognizer *)recognizer{

// 視圖前置操作

[recognizer.view.superview bringSubviewToFront:recognizer.view];

CGPoint center = recognizer.view.center;

CGFloat cornerRadius = recognizer.view.frame.size.width / 2;

CGPoint translation = [recognizer translationInView:self.view];

/**

locationView? 和 translationInView 道偷, velocityInView 的區(qū)別

1. translationInView 是UIPanGestureRecognizer下面的一個(gè)屬性

locationInView則是UIGestureRecognizer下面的屬性

2. translationInView : 獲取到的是手指移動后缀旁,在相對坐標(biāo)中的偏移量 向下和向右為正,向上和向左為勺鸦;

locationInView: 獲取到的是手指點(diǎn)擊屏幕實(shí)時(shí)的坐標(biāo)點(diǎn) 就是手指在視圖本身坐標(biāo)系的位置

velocityInView: 手指在視圖上移動的速度(x,y), 正負(fù)也是代表方向并巍,值得一體的是在絕對值上|x| > |y| 水平移動, |y|>|x| 豎直移動换途。

*/

//NSLog(@"%@", NSStringFromCGPoint(translation));

recognizer.view.center = CGPointMake(center.x + translation.x, center.y + translation.y);

[recognizer setTranslation:CGPointZero inView:self.view];

if (recognizer.state == UIGestureRecognizerStateEnded) {

//計(jì)算速度向量的長度懊渡,當(dāng)他小于200時(shí)刽射,滑行會很短

CGPoint velocity = [recognizer velocityInView:self.view];

CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));

CGFloat slideMult = magnitude / 200;

//NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult); //e.g. 397.973175, slideMult: 1.989866

//基于速度和速度因素計(jì)算一個(gè)終點(diǎn)

float slideFactor = 0.1 * slideMult;

CGPoint finalPoint = CGPointMake(center.x + (velocity.x * slideFactor),center.y + (velocity.y * slideFactor));

//限制最小[cornerRadius]和最大邊界值[self.view.bounds.size.width - cornerRadius]剃执,以免拖動出屏幕界限

finalPoint.x = MIN(MAX(finalPoint.x, cornerRadius),

self.view.bounds.size.width - cornerRadius);

finalPoint.y = MIN(MAX(finalPoint.y, cornerRadius),

self.view.bounds.size.height - cornerRadius);

//使用 UIView 動畫使 view 滑行到終點(diǎn)

[UIView animateWithDuration:slideFactor*2

delay:0

options:UIViewAnimationOptionCurveEaseOut

animations:^{

recognizer.view.center = finalPoint;

}

completion:nil];

}

}

- (void)handlePinch:(UIPinchGestureRecognizer *)recognzier{

CGFloat scale = recognzier.scale;

recognzier.view.transform = CGAffineTransformScale(recognzier.view.transform, scale, scale);// 在已縮放大小基礎(chǔ)下進(jìn)行累加變化誓禁; 區(qū)別于: 使用 CGAffineTransformMakeScale 方法就是在原大小基礎(chǔ)下進(jìn)行變化

recognzier.scale = 1.0;

}

/**

處理旋轉(zhuǎn)手勢

@param recognizer 旋轉(zhuǎn)手勢識別器對象實(shí)例

*/

- (void)handleRotation:(UIRotationGestureRecognizer *)recognizer{

recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);

recognizer.rotation = 0.0;

}

/**

處理點(diǎn)擊手勢

@param recognizer 點(diǎn)按手勢識別器對象實(shí)例

*/

- (void)handleTap:(UITapGestureRecognizer *)recognizer{

UIView *view = recognizer.view;

view.transform = CGAffineTransformMakeScale(1.0,1.0);

view.transform = CGAffineTransformMakeRotation(0.0);

view.alpha = 1.0;

}

- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer{

// 長按的時(shí)候,設(shè)置不透明度為0.7

recognizer.view.alpha = 0.7;

}

/**

處理輕掃手勢

@param recognizer 輕掃手勢識別器對象實(shí)例

*/

- (void)handleSwipe:(UISwipeGestureRecognizer *)recognizer{

//代碼塊方式封裝操作方法

void (^positionOperation)() = ^{

CGPoint newPoint = recognizer.view.center;

newPoint.y -= 20.0;

_imgV.center = newPoint;

newPoint.y += 40.0;

_imgV2.center = newPoint;

};

// 根據(jù)輕掃方向肾档,進(jìn)行不同控制

switch (recognizer.direction) {

case UISwipeGestureRecognizerDirectionRight:

positionOperation();

break;

case UISwipeGestureRecognizerDirectionLeft:

positionOperation();

break;

default:

break;

}

}

其他詳細(xì)資料: http://www.cnblogs.com/kenshincui/p/3950646.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摹恰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子怒见,更是在濱河造成了極大的恐慌俗慈,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件速种,死亡現(xiàn)場離奇詭異,居然都是意外死亡低千,警方通過查閱死者的電腦和手機(jī)配阵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來示血,“玉大人棋傍,你說我怎么就攤上這事∧焉螅” “怎么了瘫拣?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長告喊。 經(jīng)常有香客問我麸拄,道長,這世上最難降的妖魔是什么黔姜? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任拢切,我火速辦了婚禮,結(jié)果婚禮上秆吵,老公的妹妹穿的比我還像新娘淮椰。我一直安慰自己,他們只是感情好纳寂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布主穗。 她就那樣靜靜地躺著,像睡著了一般毙芜。 火紅的嫁衣襯著肌膚如雪忽媒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天腋粥,我揣著相機(jī)與錄音猾浦,去河邊找鬼陆错。 笑死,一個(gè)胖子當(dāng)著我的面吹牛金赦,可吹牛的內(nèi)容都是我干的音瓷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼夹抗,長吁一口氣:“原來是場噩夢啊……” “哼绳慎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起漠烧,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤杏愤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后已脓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體珊楼,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年度液,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厕宗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堕担,死狀恐怖已慢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霹购,我是刑警寧澤佑惠,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站齐疙,受9級特大地震影響膜楷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贞奋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一把将、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忆矛,春花似錦察蹲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漫拭,卻和暖如春亚兄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背采驻。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工审胚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匈勋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓膳叨,卻偏偏與公主長得像洽洁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子菲嘴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容