IOS七种⼿势操作(拖动、捏合、旋转、点按、长按、轻扫、⾃定义)详解及实
例代码
IOS 七种⼿势操作
今天为⼤家介绍⼀下IOS 的七种⼿势,⼿势在开发中经常⽤到,所以就简单通俗易懂的说下,话不多说,直接看代码:
1、UIGestureRecognizer 介绍
⼿势识别在 iOS 中⾮常重要,他极⼤地提⾼了移动设备的使⽤便捷性。
iOS 系统在 3.2 以后,他提供了⼀些常⽤的⼿势(UIGestureRecognizer 的⼦类),开发者可以直接使⽤他们进⾏⼿势操作。
1. UIPanGestureRecognizer(拖动)
2. UIPinchGestureRecognizer(捏合)
3. UIRotationGestureRecognizer(旋转)
4. UITapGestureRecognizer(点按)
5. UILongPressGestureRecognizer(长按)
6. U ISwipeGestureRecognizer(轻扫)
另外,可以通过继承 UIGestureRecognizer 类,实现⾃定义⼿势(⼿势识别器类)。
PS:⾃定义⼿势时,需要 #import <UIKit/UIGestureRecognizerSubclass.h>,⼀般需实现如下⽅法:
- (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 的继承关系如下:
2、⼿势状态
在六种⼿势识别中,只有⼀种⼿势是离散型⼿势,他就是 UITapGestureRecognizer。
离散型⼿势的特点就是:⼀旦识别就⽆法取消,⽽且只会调⽤⼀次⼿势操作事件(初始化⼿势时指定的回调⽅法)。
换句话说其他五种⼿势是连续型⼿势,⽽连续型⼿势的特点就是:会多次调⽤⼿势操作事件,⽽且在连续⼿势识别后可以取消⼿势。从下图可以看出两者调⽤操作事件的次数是不同的:
⼿势状态枚举如下:
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
UIGestureRecognizerStatePossible, // 尚未识别是何种⼿势操作(但可能已经触发了触摸事件),默认状态
UIGestureRecognizerStateBegan, // ⼿势已经开始,此时已经被识别,但是这个过程中可能发⽣变化,⼿势操作尚未完成
UIGestureRecognizerStateChanged, // ⼿势状态发⽣转变
UIGestureRecognizerStateEnded, // ⼿势识别操作完成(此时已经松开⼿指)
UIGestureRecognizerStateCancelled, // ⼿势被取消,恢复到默认状态
UIGestureRecognizerStateFailed, // ⼿势识别失败,恢复到默认状态
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // ⼿势识别完成,同UIGestureRecognizerStateEnded
};
对于离散型⼿势 UITapGestureRecgnizer 要么被识别,要么失败,点按(假设点按次数设置为1,并且没有添加长按⼿势)下去⼀次不松开则此时什么也不会发⽣,松开⼿指⽴即识别并调⽤操作事件,并且状态为3(已完成)。
但是连续型⼿势要复杂⼀些,就拿旋转⼿势来说,如果两个⼿指点下去不做任何操作,此时并不能识别⼿势(因为我们还没旋转)但是其实已经触发了触摸开始事件,此时处于状态0;如果此时旋转会被识别,也就会调⽤对应的操作事件,同时状态变成1(⼿势开始),但是状态1只有⼀瞬间;紧接着状态变
为2(因为我们的旋转需要持续⼀会),并且重复调⽤操作事件(如果在事件中打印状态会重复打印2);松开⼿指,此时状态变为3,并调⽤1次操作事件。
3、使⽤⼿势的步骤
使⽤⼿势很简单,分为三步:
1. 创建⼿势识别器对象实例。创建时,指定⼀个回调⽅法,当⼿势开始,改变、或结束时,执⾏回调⽅法。
2. 设置⼿势识别器对象实例的相关属性(可选部分)
3. 添加到需要识别的 View 中。每个⼿势只对应⼀个 View,当屏幕触摸在 View 的边界内时,如果⼿势和预定的⼀样,那就会执⾏回调⽅法。
PS:⼀个⼿势只能对应⼀个 View,但是⼀个 View 可以有多个⼿势。建议在真机上测试这些⼿势,模拟器操作不太⽅便,可能导致认为⼿势失效的情况。(模拟器测试捏合和旋转⼿势时,按住 option 键,再⽤触摸板或⿏标操作)
4、举例说明
功能描述:
附加到两个图⽚视图 UIImageView 的有『拖动』、『捏合』、『旋转』、『点按』;
⽽『轻扫』和『⾃定义⼿势 KMGestureRecognizer』附加在根视图 UIView 中。
拖动:进⾏当前图⽚视图位置移动
捏合:进⾏当前图⽚视图缩放
旋转:进⾏当前图⽚视图⾓度旋转
点按:双击恢复当前图⽚视图的缩放、⾓度旋转、不透明度
长按:设置当前图⽚视图的不透明度为0.7
轻扫:左右轻扫设置两个图⽚视图为居中,同时以垂直居中的特定偏移量定位
⾃定义⼿势:挠痒功能,左右扫动共3次或以上,设置两个图⽚视图为居中,同时以⽔平居中的特定偏移量定位效果如下:
KMGestureRecognizer.h
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, Direction) {
DirectionUnknown,
DirectionLeft,
DirectionRight
};
@interface KMGestureRecognizer : UIGestureRecognizer
@property (assign, nonatomic) NSUInteger tickleCount; //挠痒次数
@property (assign, nonatomic) CGPoint currentTickleStart; //当前挠痒开始坐标位置
@property (assign, nonatomic) Direction lastDirection; //最后⼀次挠痒⽅向
@end
KMGestureRecognizer.m
#import "KMGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@implementation KMGestureRecognizer
#define kMinTickleSpacing 20.0
#define kMaxTickleCount 3
- (void)reset {
_tickleCount = 0;
_currentTickleStart = CGPointZero;
_lastDirection = DirectionUnknown;
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateFailed;
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
_currentTickleStart = [touch locationInView:self.view]; //设置当前挠痒开始坐标位置
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//『当前挠痒开始坐标位置』和『移动后坐标位置』进⾏ X 轴值⽐较,得到是向左还是向右移动
UITouch *touch = [touches anyObject];
CGPoint tickleEnd = [touch locationInView:self.view];
CGFloat tickleSpacing = tickleEnd.x - _currentTickleStart.x;
Direction currentDirection = tickleSpacing < 0 ? DirectionLeft : DirectionRight;
//移动的 X 轴间距值是否符合要求,⾜够⼤
if (ABS(tickleSpacing) >= kMinTickleSpacing) {
//判断是否有三次不同⽅向的动作,如果有则⼿势结束,将执⾏回调⽅法
if (_lastDirection == DirectionUnknown ||
(_lastDirection == DirectionLeft && currentDirection == DirectionRight) ||
(_lastDirection == DirectionRight && currentDirection == DirectionLeft)) {
_tickleCount++;
_currentTickleStart = tickleEnd;
_lastDirection = currentDirection;
if (_tickleCount >= kMaxTickleCount && self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateEnded;
//NSLog(@"⾃定义⼿势成功,将执⾏回调⽅法");
}
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self reset];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self reset];
}
@end
ViewController.h
#import <UIKit/UIKit.h>
#import "KMGestureRecognizer.h"
@interface ViewController : UIViewController
@property (strong, nonatomic) UIImageView *imgV;
@property (strong, nonatomic) UIImageView *imgV2;
@property (strong, nonatomic) KMGestureRecognizer *customGestureRecognizer;
@end
ViewController.m
#import "ViewController.h"
@interface ViewController ()
- (void)handlePan:(UIPanGestureRecognizer *)recognizer;
- (void)handlePinch:(UIPinchGestureRecognizer *)recognizer;
- (void)handleRotation:(UIRotationGestureRecognizer *)recognizer;
- (void)handleTap:(UITapGestureRecognizer *)recognizer;
- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer;
- (void)handleSwipe:(UISwipeGestureRecognizer *)recognizer;
- (void)handleCustomGestureRecognizer:(KMGestureRecognizer *)recognizer;
- (void)bindPan:(UIImageView *)imgVCustom;
-
(void)bindPinch:(UIImageView *)imgVCustom;
- (void)bindRotation:(UIImageView *)imgVCustom;
- (void)bindTap:(UIImageView *)imgVCustom;
- (void)bindLongPress:(UIImageView *)imgVCustom;
- (void)bindSwipe;
- (void)bingCustomGestureRecognizer;
- (void)layoutUI;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self layoutUI];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - 处理⼿势操作
/**
* 处理拖动⼿势
*
* @param recognizer 拖动⼿势识别器对象实例
*/
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
//视图前置操作
[recognizer.view.superview bringSubviewToFront:recognizer.view];
CGPoint center = ;
CGFloat cornerRadius = recognizer.view.frame.size.width / 2;
CGPoint translation = [recognizer translationInView:self.view];
//NSLog(@"%@", NSStringFromCGPoint(translation));
= CGPointMake(center.x + translation.x, center.y + translation.y);
[recognizer setTranslation:CGPointZero inView:self.view];
if (recognizer.state == UIGestureRecognizerStateEnded) {
/
/计算速度向量的长度,当他⼩于200时,滑⾏会很短
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
//基于速度和速度因素计算⼀个终点
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 滑⾏到终点
[UIView animateWithDuration:slideFactor*2
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
= finalPoint;
}
completion:nil];
}
}
/**
* 处理捏合⼿势
*
* @param recognizer 捏合⼿势识别器对象实例
*/
- (void)handlePinch:(UIPinchGestureRecognizer *)recognizer {
CGFloat scale = recognizer.scale;
ansform = CGAffineTransformScale(ansform, scale, scale); //在已缩
放⼤⼩基础下进⾏累加变化;区别于:使⽤ CGAffineTransformMakeScale ⽅法就是在原⼤⼩基础下进⾏变化 recognizer.scale = 1.0;
}
/**
* 处理旋转⼿势
*
* @param recognizer 旋转⼿势识别器对象实例
*/
- (void)handleRotation:(UIRotationGestureRecognizer *)recognizer {
ansform = CGAffineTransformRotate(ansform, ation);
}
/**
* 处理点按⼿势
*
* @param recognizer 点按⼿势识别器对象实例
*/
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
UIView *view = recognizer.view;
view.alpha = 1.0;
}
/
**
* 处理长按⼿势
*
* @param recognizer 点按⼿势识别器对象实例
*/
- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer {
//长按的时候,设置不透明度为0.7
recognizer.view.alpha = 0.7;
}
/**
* 处理轻扫⼿势
*
* @param recognizer 轻扫⼿势识别器对象实例
*/
- (void)handleSwipe:(UISwipeGestureRecognizer *)recognizer {
//代码块⽅式封装操作⽅法
void (^positionOperation)() = ^() {
CGPoint newPoint = ;
newPoint.y -= 20.0;
_ = newPoint;
newPoint.y += 40.0;
_ = newPoint;
};
//根据轻扫⽅向,进⾏不同控制
switch (recognizer.direction) {
case UISwipeGestureRecognizerDirectionRight: {
positionOperation();
break;
}
case UISwipeGestureRecognizerDirectionLeft: {
positionOperation();
break;
}
case UISwipeGestureRecognizerDirectionUp: {
break;
}
case UISwipeGestureRecognizerDirectionDown: {
break;
}
}
}
/**
* 处理⾃定义⼿势
*
* @param recognizer ⾃定义⼿势识别器对象实例
*/
- (void)handleCustomGestureRecognizer:(KMGestureRecognizer *)recognizer {
//代码块⽅式封装操作⽅法
void (^positionOperation)() = ^() {
CGPoint newPoint = ;
newPoint.x -= 20.0;
_ = newPoint;
newPoint.x += 40.0;
_ = newPoint;
};
positionOperation();
}
#pragma mark - 绑定⼿势操作
/**
* 绑定拖动⼿势
*
* @param imgVCustom 绑定到图⽚视图对象实例
*/
- (void)bindPan:(UIImageView *)imgVCustom {
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
[imgVCustom addGestureRecognizer:recognizer];
}
/**
* 绑定捏合⼿势
*
* @param imgVCustom 绑定到图⽚视图对象实例
*/
- (void)bindPinch:(UIImageView *)imgVCustom {
UIPinchGestureRecognizer *recognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePinch:)];
[imgVCustom addGestureRecognizer:recognizer];
/
/[recognizer stureRecognizers.firstObject];
}
/**
* 绑定旋转⼿势
*
* @param imgVCustom 绑定到图⽚视图对象实例
*/
- (void)bindRotation:(UIImageView *)imgVCustom {
UIRotationGestureRecognizer *recognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotation:)];
[imgVCustom addGestureRecognizer:recognizer];
}
/**
* 绑定点按⼿势
*
* @param imgVCustom 绑定到图⽚视图对象实例
*/
- (void)bindTap:(UIImageView *)imgVCustom {
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTap:)];
//使⽤⼀根⼿指双击时,才触发点按⼿势识别器
recognizer.numberOfTapsRequired = 2;
recognizer.numberOfTouchesRequired = 1;
[imgVCustom addGestureRecognizer:recognizer];
}
/**
* 绑定长按⼿势
*
* @param imgVCustom 绑定到图⽚视图对象实例
*/
- (void)bindLongPress:(UIImageView *)imgVCustom {
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; recognizer.minimumPressDuration = 0.5; //设置最⼩长按时间;默认为0.5秒
[imgVCustom addGestureRecognizer:recognizer];
}
/**
* 绑定轻扫⼿势;⽀持四个⽅向的轻扫,但是不同的⽅向要分别定义轻扫⼿势
*/
- (void)bindSwipe {
//向右轻扫⼿势
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSwipe:)];
recognizer.direction = UISwipeGestureRecognizerDirectionRight; //设置轻扫⽅向;默认是 UISwipeGestureRecognizerDirectionRight,即向右轻扫 [self.view addGestureRecognizer:recognizer];
[recognizer requireGestureRecognizerToFail:_customGestureRecognizer]; //设置以⾃定义挠痒⼿势优先识别
//向左轻扫⼿势
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSwipe:)];
recognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:recognizer];
[recognizer requireGestureRecognizerToFail:_customGestureRecognizer]; //设置以⾃定义挠痒⼿势优先识别
}
/**
* 绑定⾃定义挠痒⼿势;判断是否有三次不同⽅向的动作,如果有则⼿势结束,将执⾏回调⽅法
*/
- (void)bingCustomGestureRecognizer {
//当 recognizer.state 为 UIGestureRecognizerStateEnded 时,才执⾏回调⽅法 handleCustomGestureRecognizer:
//_customGestureRecognizer = [KMGestureRecognizer new];
_customGestureRecognizer = [[KMGestureRecognizer alloc] initWithTarget:self
action:@selector(handleCustomGestureRecognizer:)];
[self.view addGestureRecognizer:_customGestureRecognizer];
}
- (void)layoutUI {
//图⽚视图 _imgV
tickleUIImage *img = [UIImage imageNamed:@"Emoticon_tusiji_icon"];
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;
_Radius = cornerRadius;
_imgV.layer.borderWidth = 2.0;
_imgV.layer.borderColor = [UIColor grayColor].CGColor;
[self.view addSubview:_imgV];
//图⽚视图 _imgV2
img = [UIImage imageNamed:@"Emoticon_tusiji_icon2"];
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;
_Radius = cornerRadius;
_imgV2.layer.borderWidth = 2.0;
_imgV2.layer.borderColor = [UIColor orangeColor].CGColor;
[self.view addSubview:_imgV2];
[self bindPan:_imgV];
[self bindPinch:_imgV];
[self bindRotation:_imgV];
[self bindTap:_imgV];
[self bindLongPress:_imgV];
[self bindPan:_imgV2];
[self bindPinch:_imgV2];
[self bindRotation:_imgV2];
[self bindTap:_imgV2];
[self bindLongPress:_imgV2];
//为了处理⼿势识别优先级的问题,这⾥需先绑定⾃定义挠痒⼿势
[self bingCustomGestureRecognizer];
[self bindSwipe];
}
@end
感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论