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