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+CWCategoryUIImage+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次"); }
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- android使用gesturedetector手势识别示例分享
- js判断客户端是iOS还是Android等移动终端的方法
- IOS开发环境windows化攻略
- .net平台推送ios消息的实现方法
- 探讨Android与iOS,我们将何去何从?
- Android、iOS和Windows Phone中的推送技术详解
- IOS 改变键盘颜色代码
- 举例详解iOS开发过程中的沙盒机制与文件
- Android和IOS的浏览器中检测是否安装某个客户端的方法
- javascript实现阻止iOS APP中的链接打开Safari浏览器
- IOS开发第三方语音-微信语音
- iOS开发之路--微博OAuth授权_取得用户授权的accessToken
- 基于UIControl控件实现ios点赞功能