您的位置:首页 > 产品设计 > UI/UE

iOS 手势识别与操作 UIGestureRecognizer

2015-09-21 23:16 591 查看

1.UIGestureRecognizer

UITapGestureRecognizer 轻拍手势

UIPinchGestureRecognizer 捏合缩放

UIRotationGestureRecognizer 旋转

UISwipeGestureRecognizer 轻扫滑动

UIPanGestureRecognizer 拖移

UILongPressGestureRecognizer 长按

2.注意事项

当为手势添加回调方法时,手势开始,改变、或结束时,回调方法被调用,有的时候只需要调用一次方法,可以用gesture的state属性来判断,如if (gesture.state == UIGestureRecognizerStateBegan) {}

3.TapGesture

self.view.backgroundColor = [UIColor lightGrayColor];
self.gv.layer.borderWidth = 2;
self.gv.layer.cornerRadius = 6;
// 设置gv控件支持用户交互
self.gv.userInteractionEnabled = YES;
// 设置gv控件支持多点触碰
self.gv.multipleTouchEnabled = YES;
for (int i = 1 ; i < 6 ; i++)
{
// 创建手势处理器,指定使用该控制器的handleTap:方法处理手势
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleTap:)];
// 设置该点击手势处理器只处理i次连击事件
gesture.numberOfTapsRequired = i;
// 设置该点击手势处理器只处理2个手指的触碰事件
gesture.numberOfTouchesRequired = 1;
// 为gv控件添加手势处理器。
[self.gv addGestureRecognizer:gesture];
}
}
// 实现手势处理器的方法,该方法应该声明一个形参。
// 当该方法被激发时,手势处理器会作为参数传给该方法的参数。
- (void) handleTap:(UITapGestureRecognizer*)gesture
{
NSUInteger touchNum = gesture.numberOfTouches;
NSUInteger tapNum = gesture.numberOfTapsRequired;
self.label.text = [NSString stringWithFormat:
@"用户使用%lu个手指进行触碰,触碰次数为:%lu" , touchNum , tapNum];
// 指定2秒后清除label的文本
[self.label performSelector:@selector(setText:)
withObject:@"" afterDelay:2];
}


4.PinchGesture

- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
self.gv.layer.borderWidth = 2;
self.gv.layer.cornerRadius = 6;
// 设置gv控件支持用户交互
self.gv.userInteractionEnabled = YES;
// 设置gv控件支持多点触碰
self.gv.multipleTouchEnabled = YES;
// 创建手势处理器,指定使用该控制器的handlePinch:方法处理手势
UIPinchGestureRecognizer* gesture = [[UIPinchGestureRecognizer alloc]
initWithTarget:self action:@selector(handlePinch:)];
// 为gv控件添加手势处理器。
[self.gv addGestureRecognizer:gesture];
}
// 实现手势处理器的方法,该方法应该声明一个形参。
// 当该方法被激发时,手势处理器会作为参数传给该方法的参数。
- (void) handlePinch:(UIPinchGestureRecognizer*)gesture
{
// 获取用户捏合的速度和比例
CGFloat velocity = gesture.velocity;
CGFloat scale = gesture.scale;
self.label.text = [NSString stringWithFormat:
@"用户捏合的速度为%g、比例为%g" , velocity , scale];
// 指定2秒后清除label的文本
//[self.label performSelector:@selector(setText:)
//  withObject:@"" afterDelay:2];
}


5.RotationGesture 仿iPhone相册图片捏合旋转

1.扩展UIImage:UIImage+CWCategory

UIImage+CWCategory.h

@interface UIImage (CWCategory)
// 对指定UI控件进行截图
+ (UIImage*)captureView:(UIView *)targetView;
//+ (UIImage*)captureScreen;
// 定义一个方法用于“挖取”图片的指定区域
- (UIImage *)imageAtRect:(CGRect)rect;
// 保持图片纵横比缩放,最短边必须匹配targetSize的大小
// 可能有一条边的长度会超过targetSize指定的大小
- (UIImage *)imageByScalingAspectToMinSize:(CGSize)targetSize;
// 保持图片纵横比缩放,最长边匹配targetSize的大小即可
// 可能有一条边的长度会小于targetSize指定的大小
- (UIImage *)imageByScalingAspectToMaxSize:(CGSize)targetSize;
// 不保持图片纵横比缩放
- (UIImage *)imageByScalingToSize:(CGSize)targetSize;
// 对图片按弧度执行旋转
- (UIImage *)imageRotatedByRadians:(CGFloat)radians;
// 对图片按角度执行旋转
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;
- (void) saveToDocuments:(NSString*)fileName;
@end


UIImage+CWCategory.m:

#import "UIImage+CWCategory.h"
#import <QuartzCore/QuartzCore.h>

//extern CGImageRef UIGetScreenImage();
@implementation UIImage (CWCategory)
//+ (UIImage*)captureScreen
//{
//  // 需要先声明该外部函数
//  extern CGImageRef UIGetScreenImage();
//  // 调用UIGetScreenImage()函
1298b
数执行截屏
//  CGImageRef screen = UIGetScreenImage();
//  // 获取截屏得到的图片
//  UIImage* newImage = [UIImage imageWithCGImage:screen];
//  return newImage;
//}
+ (UIImage*)captureView:(UIView *)targetView
{
// 获取目标UIView的所在的区域
CGRect rect = targetView.frame;
// 开始绘图
UIGraphicsBeginImageContext(rect.size);
// 获取当前的绘图Context
CGContextRef context = UIGraphicsGetCurrentContext();
// 调用CALayer的方法将当前控件绘制到绘图Context中
[targetView.layer renderInContext:context];
// 获取该绘图Context中的图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
-(UIImage *)imageAtRect:(CGRect)rect
{
// 获取该UIImage图片对应的CGImageRef对象
CGImageRef srcImage = [self CGImage];
// 从srcImage中“挖取”rect区域
CGImageRef imageRef = CGImageCreateWithImageInRect(srcImage, rect);
// 将“挖取”出来的CGImageRef转换为UIImage对象
UIImage* subImage = [UIImage imageWithCGImage: imageRef];
CGImageRelease(srcImage);
CGImageRelease(imageRef);
return subImage;
}
- (UIImage *)imageByScalingAspectToMinSize:(CGSize)targetSize
{
// 获取源图片的宽和高
CGSize imageSize = self.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
// 获取图片缩放目标大小的宽和高
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
// 定义图片缩放后的宽度
CGFloat scaledWidth = targetWidth;
// 定义图片缩放后的高度
CGFloat scaledHeight = targetHeight;
CGPoint anchorPoint = CGPointZero;
// 如果源图片的大小与缩放的目标大小不相等
if (!CGSizeEqualToSize(imageSize, targetSize))
{
// 计算水平方向上的缩放因子
CGFloat xFactor = targetWidth / width;
// 计算垂直方向上的缩放因子
CGFloat yFactor = targetHeight / height;
// 定义缩放因子scaleFactor,为两个缩放因子中较大的一个
CGFloat scaleFactor = xFactor > yFactor? xFactor : yFactor;
// 根据缩放因子计算图片缩放后的宽度和高度
scaledWidth  = width * scaleFactor;
scaledHeight = height * scaleFactor;
// 如果横向上的缩放因子大于纵向上的缩放因子,那么图片在纵向上需要裁切
if (xFactor > yFactor)
{
anchorPoint.y = (targetHeight - scaledHeight) * 0.5;
}
// 如果横向上的缩放因子小于纵向上的缩放因子,那么图片在横向上需要裁切
else if (xFactor < yFactor)
{
anchorPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
// 开始绘图
UIGraphicsBeginImageContext(targetSize);
// 定义图片缩放后的区域
CGRect anchorRect = CGRectZero;
anchorRect.origin = anchorPoint;
anchorRect.size.width  = scaledWidth;
anchorRect.size.height = scaledHeight;
// 将图片本身绘制到auchorRect区域中
[self drawInRect:anchorRect];
// 获取绘制后生成的新图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 返回新图片
return newImage ;
}
- (UIImage *)imageByScalingAspectToMaxSize:(CGSize)targetSize
{
// 获取源图片的宽和高
CGSize imageSize = self.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
// 获取图片缩放目标大小的宽和高
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
// 定义图片缩放后的实际的宽和高度
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint anchorPoint = CGPointZero;
// 如果源图片的大小与缩放的目标大小不相等
if (!CGSizeEqualToSize(imageSize, targetSize))
{
CGFloat xFactor = targetWidth / width;
CGFloat yFactor = targetHeight / height;
// 定义缩放因子scaleFactor,为两个缩放因子中较小的一个
CGFloat scaleFactor = xFactor < yFactor ? xFactor:yFactor;
// 根据缩放因子计算图片缩放后的宽度和高度
scaledWidth  = width * scaleFactor;
scaledHeight = height * scaleFactor;
// 如果横向的缩放因子小于纵向的缩放因子,图片在上面、下面有空白
// 那么图片在纵向上需要下移一段距离,保持图片在中间
if (xFactor < yFactor)
{
anchorPoint.y = (targetHeight - scaledHeight) * 0.5;
}
// 如果横向的缩放因子小于纵向的缩放因子,图片在左边、右边有空白
// 那么图片在横向上需要右移一段距离,保持图片在中间
else if (xFactor > yFactor)
{
anchorPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
// 开始绘图
UIGraphicsBeginImageContext(targetSize);
// 定义图片缩放后的区域
CGRect anchorRect = CGRectZero;
anchorRect.origin = anchorPoint;
anchorRect.size.width  = scaledWidth;
anchorRect.size.height = scaledHeight;
// 将图片本身绘制到auchorRect区域中
[self drawInRect:anchorRect];
// 获取绘制后生成的新图片
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 返回新图片
return newImage ;
}
- (UIImage *)imageByScalingToSize:(CGSize)targetSize
{
// 开始绘图
UIGraphicsBeginImageContext(targetSize);
// 定义图片缩放后的区域,因此无需保持纵横比,所以直接缩放
CGRect anchorRect = CGRectZero;
anchorRect.origin = CGPointZero;
anchorRect.size = targetSize;
// 将图片本身绘制到auchorRect区域中
[self drawInRect:anchorRect];
// 获取绘制后生成的新图片
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 返回新图片
return newImage;
}
// 图片旋转角度
- (UIImage *)imageRotatedByRadians:(CGFloat)radians
{
// 定义一个执行旋转的CGAffineTransform结构体
CGAffineTransform t = CGAffineTransformMakeRotation(radians);
// 对图片的原始区域执行旋转,获取旋转后的区域
CGRect rotatedRect = CGRectApplyAffineTransform(
CGRectMake(0.0 , 0.0, self.size.width, self.size.height) , t);
// 获取图片旋转后的大小
CGSize rotatedSize = rotatedRect.size;
// 创建绘制位图的上下文
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 指定坐标变换,将坐标中心平移到图片的中心
CGContextTranslateCTM(ctx, rotatedSize.width/2, rotatedSize.height/2);
// 执行坐标变换,旋转过radians弧度
CGContextRotateCTM(ctx , radians);
// 执行坐标变换,执行缩放
CGContextScaleCTM(ctx, 1.0, -1.0);
// 绘制图片
CGContextDrawImage(ctx, CGRectMake(-self.size.width / 2
, -self.size.height / 2,
self.size.width,
self.size.height), self.CGImage);
// 获取绘制后生成的新图片
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 返回新图片
return newImage;
}
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
{
return [self imageRotatedByRadians:degrees * M_PI / 180];
}
- (void) saveToDocuments:(NSString*)fileName
{
// 获取当前应用路径下的Documents目录下的指定文件名对应的文件路径
NSString *path = [[NSHomeDirectory()
stringByAppendingPathComponent:@"Documents"]
stringByAppendingPathComponent:fileName];
// 保存PNG图片
[UIImagePNGRepresentation(self)
writeToFile:path atomically:YES];
//  // 保存JPG图片
//  [UIImageJPEGRepresentation(self, 1.0) // 1.0代表图片压缩比率
//      writeToFile:path atomically:YES];
}
@end


ViewController:

#import "UIImage+CWCategory.h"

#define PI 3.141592653
#define degtorad(X) ((X)/180*PI)
#define radtodeg(X) ((X)*180/PI)

@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@end

@implementation ViewController
UIImage* srcImage;
CGFloat currentScale;
CGFloat currentRotation;
- (void)viewDidLoad
{
[super viewDidLoad];
[UIApplication sharedApplication].statusBarHidden = YES;
srcImage = [UIImage imageNamed:@"seashore.png"];
// 设置图片直接显示在中间(不进行任何缩放)
self.view.contentMode = UIViewContentModeCenter;
// 设置imageView初始显示的图片
self.imageView.image = srcImage;
// 设置初始的缩放比例
currentScale = 1;
currentRotation = 0;
// 设置imageView允许用户交互,支持多点触碰
self.imageView.userInteractionEnabled = YES;
self.imageView.multipleTouchEnabled = YES;
// 创建UIPinchGestureRecognizer手势处理器,该手势处理器激发scaleImage:方法
UIPinchGestureRecognizer* gesture = [[UIPinchGestureRecognizer alloc]
initWithTarget:self action:@selector(scaleImage:)];
// 为imageView添加手势处理器
[self.imageView addGestureRecognizer:gesture];
// 创建UIRotationGestureRecognizer手势处理器,该手势处理器激发rotateImage:方法
UIRotationGestureRecognizer* rotateGesture =
[[UIRotationGestureRecognizer alloc]
initWithTarget:self action:@selector(rotateImage:)];
// 为imageView添加手势处理器
[self.imageView addGestureRecognizer:rotateGesture];
}
- (void) scaleImage:(UIPinchGestureRecognizer*)gesture
{
CGFloat scale = gesture.scale;
// 根据手势处理器的缩放比计算图片缩放后的目标大小
CGSize targetSize = CGSizeMake(srcImage.size.width * scale * currentScale,
srcImage.size.height * scale * currentScale);
// 对图片进行缩放、旋转
self.imageView.image = [[srcImage imageByScalingToSize:targetSize]
imageRotatedByRadians:currentRotation];
// 如果手势结束
if(gesture.state == UIGestureRecognizerStateEnded)
{
// 计算结束时候图片的缩放比
currentScale = scale * currentScale;
}
}

- (void) rotateImage:(UIRotationGestureRecognizer*)gesture
{
// 获取手势旋转的弧度
CGFloat rotation = gesture.rotation;

//NSLog(@"rotation %f",rotation);
//NSLog(@"du %f",radtodeg(rotation));

// 根据当前缩放比计算图片缩放后的目标大小
CGSize targetSize = CGSizeMake(srcImage.size.width * currentScale,
srcImage.size.height * currentScale);
// 对图片进行缩放、旋转
self.imageView.image = [[srcImage imageByScalingToSize:targetSize]
imageRotatedByRadians:currentRotation + rotation];
// 如果旋转手势结束
if(gesture.state == UIGestureRecognizerStateEnded)
{
currentRotation = currentRotation + rotation;
}
}
@end


6.SwipeGesture

- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
self.gv.layer.borderWidth = 2;
self.gv.layer.cornerRadius = 6;
// 设置gv控件支持用户交互
self.gv.userInteractionEnabled = YES;
// 设置gv控件支持多点触碰
self.gv.multipleTouchEnabled = YES;
for (int i = 0 ; i < 4 ; i++)
{
// 创建手势处理器,指定使用该控制器的handleSwipe:方法处理轻扫手势
UISwipeGestureRecognizer* gesture = [[UISwipeGestureRecognizer alloc]
initWithTarget:self action:@selector(handleSwipe:)];
// 设置该点击手势处理器只处理i个手指的轻扫手势
gesture.numberOfTouchesRequired = 1;
// 指定该手势处理器只处理1 << i方向的轻扫手势

gesture.direction = 1<<i;
// 为gv控件添加手势处理器。
[self.gv addGestureRecognizer:gesture];
}

}
// 实现手势处理器的方法,该方法应该声明一个形参。
// 当该方法被激发时,手势处理器会作为参数传给该方法的参数。
- (void) handleSwipe:(UISwipeGestureRecognizer*)gesture
{
// 获取轻扫手势的方向
NSUInteger direction = gesture.direction;
// 根据手势方向的值得到方向字符串
NSString* dirStr = direction == UISwipeGestureRecognizerDirectionRight
? @"向右" : (direction == UISwipeGestureRecognizerDirectionLeft
? @"向左" : (direction == UISwipeGestureRecognizerDirectionUp
? @"向上" :@"向下"));
NSUInteger touchNum = gesture.numberOfTouchesRequired;
self.label.text = [NSString stringWithFormat:
@"用户使用%lu个手指进行轻扫,方向为:%@" , (unsigned long)touchNum , dirStr];
// 指定2秒后清除label的文本
[self.label performSelector:@selector(setText:)
withObject:@"" afterDelay:2];
}


7.PanGesture

(void)viewDidLoad

{

[super viewDidLoad];

self.view.backgroundColor = [UIColor lightGrayColor];

self.gv.layer.borderWidth = 2;

self.gv.layer.cornerRadius = 6;

// 设置gv控件支持用户交互

self.gv.userInteractionEnabled = YES;

// 设置gv控件支持多点触碰

self.gv.multipleTouchEnabled = YES;

// 创建手势处理器,指定使用该控制器的handlePan:方法处理手势

UIPanGestureRecognizer* gesture = [[UIPanGestureRecognizer alloc]

initWithTarget:self action:@selector(handlePan:)];

// 设置该拖动手势处理器至少需要1个手指

gesture.minimumNumberOfTouches = 1;

// 设置该拖动手势处理器最多需要2个手指

gesture.maximumNumberOfTouches = 2;

// 为gv控件添加手势处理器。

[self.gv addGestureRecognizer:gesture];

}

// 实现手势处理器的方法,该方法应该声明一个形参。

// 当该方法被激发时,手势处理器会作为参数传给该方法的参数。

(void) handlePan:(UIPanGestureRecognizer*)gesture

{

CGPoint velocity = [gesture velocityInView:self.gv];

CGPoint translation = [gesture translationInView:self.gv];

self.label.text = [NSString stringWithFormat:

@”水平速度为:%g, 垂直速度为:%g, 水平位移为:%g, 垂直位移为:%g”

, velocity.x , velocity.y

, translation.x , translation.y];

// 指定2秒后清除label的文本

//[self.label performSelector:@selector(setText:)

// withObject:@”” afterDelay:2];

}

8.LongPressGesture

#define BUTTON_WIDTH 80
#define BUTTON_HEIGHT 30

@implementation ViewController
NSInteger bnIndex;

- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];

// 创建一个手势处理器,用于检测、处理长按手势
UILongPressGestureRecognizer* gesture = [[UILongPressGestureRecognizer
alloc]initWithTarget:self action:@selector(longPress:)];
// 为该控件添加手势处理器
[self.view addGestureRecognizer:gesture];

}

- (void) panAction:(UIPanGestureRecognizer*)gesture {
CGPoint point = [gesture locationInView:self.view];
UIButton * btn = (UIButton*)[gesture view];
[btn setFrame:CGRectMake(point.x - BUTTON_WIDTH/2 , point.y - BUTTON_HEIGHT/2, BUTTON_WIDTH, BUTTON_HEIGHT)];
}

- (void) longPress:(UILongPressGestureRecognizer*)gesture
{

CGPoint point = [gesture locationInView:self.view];

,
UIButton* bn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
// 为该按钮设置文本
[bn setTitle:[NSString stringWithFormat:@"按钮%ld", (long)bnIndex]
forState:UIControlStateNormal];
// 设置该bn按钮的大小和位置
bn.frame = CGRectMake( point.x,point.y, BUTTON_WIDTH , BUTTON_HEIGHT);
// 为该按钮添加事件处理方法
[bn addTarget:self action:@selector(remove:)
forControlEvents:UIControlEventTouchUpInside];

// 将按钮添加到应用界面的UIView控件中
[self.view addSubview:bn];

UIPanGestureRecognizer * panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[bn addGestureRecognizer:panGesture];

bnIndex ++;
}

}
- (void) remove:(UIButton*)sender
{
for (UIGestureRecognizer * ges in [sender gestureRecognizers]) {
[sender removeGestureRecognizer:ges];
}

// 删除事件源控件(激发该事件的按钮)
[sender removeFromSuperview];

}

@end


9.手势的依赖

[A requireGestureRecognizerToFail:B]函数,它可以指定当A手势发生时,即便A已经滿足条件了,也不会立刻触发,会等到指定的手势B确定失败之后才触发。

- (void)viewDidLoad {
[super viewDidLoad];
// 轻拍1次
UITapGestureRecognizer* tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(SingleTap:)];
//点击的次数
tap1.numberOfTapsRequired = 1;
//给self.view添加一个手势监测;
[self.view addGestureRecognizer:tap1];

// 轻拍2次
UITapGestureRecognizer* tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(DoubleTap:)];
tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(DoubleTap:)];
tap2.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:tap2];

// 手势互斥或依赖,双击手势确定监测失败才会触发单击手势的相应操作
[tap1 requireGestureRecognizerToFail:tap2];

}

-(void)SingleTap:(UITapGestureRecognizer*)recognizer
{
NSLog(@"轻拍1次");

}

-(void)DoubleTap:(UITapGestureRecognizer*)recognizer
{
NSLog(@"轻拍2次");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios 手势识别 UIGesture