iPhone/iPad高级应用与手游开发学习笔记:多点触摸与手势检测(三:UIPinchGestureRecognizer和UIRotationGestureRecognizer)
先说一件不幸的事情,本人中午打篮球,不慎脚拐了......悲催啊,愚人节,但是这件事情绝不愚人。
言归正传,上一篇学习了捏合手势,这一篇中我们学习旋转手势,并且使用旋转和捏合做一个操作图片的例子
使用UIRotationGestureRecognizer处理旋转手势的步骤与使用其他手势处理器的步骤完全相同,UIRotationGestureRecognizer定义了如下两个属性来获取旋转相关信息:
rotation:获取旋转角度
velocity: 获取旋转速度
例子:
一.创建一个带有xib或者storyboard的simple view application
二,给storyboard后者xib中拖一个UIImage视图
三,创建一个category,代码如下:
类别头文件:
#import <UIKit/UIKit.h>
实现类:
#import "UIImage+FKCategory.h"
#import <QuartzCore/QuartzCore.h>
@implementation UIImage (FKCategory)
+(UIImage *) captureScreen
{
//需要先声明该外部函数
extern CGImageRef UIGetScreenImage();
//调用UIGetScreenImage()函数执行截屏
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 { //如果横向上德缩放因子小于纵向上德缩放因子,那么图片在横向上需要裁切
anchorPoint.x = (targetWidth -scaledWidth) * 0.5;
}
}
//开始绘图
UIGraphicsBeginImageContext(targetSize);
//定义图片缩放后的区域
CGRect anchorRect = CGRectZero;
anchorRect.origin = anchorPoint;
anchorRect.size.width = scaledWidth;
anchorRect.size.height = scaledHeight;
//将图片本身绘制到anchorRect区域中
[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;
//将图片本身绘制到anchorRect区域中
[self drawInRect:anchorRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
-(UIImage *) imageByScalingToSize:(CGSize)targetSize
{
//开始绘图
UIGraphicsBeginImageContext(targetSize);
//定义图片缩放后的区域,因此无需保持纵横比,所以直接缩放
CGRect anchorRect = CGRectZero;
anchorRect.origin = CGPointZero;
anchorRect.size = targetSize;
//将图片本身绘制到anchorRect区域中
[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 *) imageRotatedByDegress:(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];
}
@end
四,完成之后再在项目自动生成的视图控制器的头文件中加入你拖进去的UIImageView属性,注意,应该是IBOutlet的。然后在实现类中得代码如下:
#import "ViewController.h"
#import "UIImage+FKCategory.h"
@interface ViewController ()
@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:)];
[self.imageView addGestureRecognizer:rotateGesture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(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;
// 根据当前缩放比计算图片缩放后的目标大小
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
五,最后别忘记在xib或者storyboard中给UIImageView的属性连线
最后效果如下图:
iPhone/iPad高级应用与手游开发学习笔记:多点触摸与手势检测(三:UIPinchGestureRecognizer和UIRotationGestureRecognizer)相关推荐
- iPhone iPad高级编程
iPhone & iPad高级编程 编辑推荐 1. 本书中的示例颇具价值,浓缩了iPhone和iPad编程智慧,具有新颖独到之处.开发人员在日常工作中可以参考这些绝佳示例迅速找到解决方案.不管 ...
- 视频教程-红孩儿网狐Cocos经典棋牌开发教程-手游开发
红孩儿网狐Cocos经典棋牌开发教程 中国早期游戏程序员,2003年起从事游戏程序开发,负责开发过多款游戏项目,曾担任大型端游<无限世界>自研引擎技术负责人,2012年起关注Cocos引擎 ...
- 视频教程-Layabox3D游戏视频教程-源码-手游开发
Layabox3D游戏视频教程-源码 有多年Unity程序开发经验,有策划和美术设计的经验.愿意在csdn这个平台和大家一起分享! 金龙 ¥49.00 立即订阅 扫码下载「CSDN程序员学院APP」, ...
- 视频教程-微信小程序系统教程python版[3/3阶段]_微信小程序支付-手游开发
微信小程序系统教程python版[3/3阶段]_微信小程序支付 微信企业号星级会员.10多年软件从业经历,国家级软件项目负责人,主要从事软件研发.软件企业员工技能培训.已经取得计算机技术与软件资格考试 ...
- 视频教程-使用Cocos2d-x 开发3D游戏-手游开发
使用Cocos2d-x 开发3D游戏 中国早期游戏程序员,2003年起从事游戏程序开发,负责开发过多款游戏项目,曾担任大型端游<无限世界>自研引擎技术负责人,2012年起关注Cocos引擎 ...
- 视频教程-H5入门-系列手机游戏开发-过河-手游开发
H5入门-系列手机游戏开发-过河 20年软件项目开发管理经验 工信部人才交流中心特聘专家讲师 日本U-CAN在线教育特聘主任讲师 国家十二·五规划软件工程教材作者(书:清华大学出版社出版) 中国软件行 ...
- Unity手游开发札记——移动平台的天气系统实现
0. 牢骚 我发现,每个月的20+号是我有精力写博客的时间-- 这次项目算是经历的第一次严格意义上的渠道测试,更换了正式名称,见了更多玩家,开发组也经历的更多通宵--评价和数据如何暂时还未揭晓,趁着没 ...
- Cocos2d-x 手游开发群:296733909
2019独角兽企业重金招聘Python工程师标准>>> #Cocos2d-x 手游开发群:296733909 转载于:https://my.oschina.net/skyhacker ...
- 一 手游开发工具cocos2d-x editor初识
可学习的demo: 7个实战项目 flappybird(飞扬小鸟).popstar(消灭星星).fruitninja(水果忍者).2048(数度消除). moonwarriors(月亮战神).frui ...
最新文章
- 【机器学习】数据不平衡问题都怎么解?
- c语言ascw,VBS中的Asc/AscB/AscW和Chr/ChrB/ChrW函数之间的区别
- Hibernate3 jar包的作用[转]
- 专科学python真的不好_专科生转行做python运维靠谱吗?
- 2019后工作机会会更少_在2019年更多地参与和更少地命令
- ic 卡获取帐号apdu指令_《全球行动》携手京东校园送福利 1000元京东卡等你拿
- Spring学习总结(22)——spring-framework-bom解决spring的不同模块依赖版本不同问题...
- 切线理论-支撑位与阻力位
- 华为的型号命名规则_iQOO新品入网;三星Galaxy S21首张官方渲染图曝光;华为nova8真机曝光...
- iOS 录音功能实现
- 智能优化算法——差分进化算法(Python实现)
- 计算机报时间校准错误无法启动,【北京时间同步如何校准?】电脑时间同步服务器地址出错怎么办?...
- C#使用libVLC制作视频播放器时自定义鼠标事件的捕获或者忽略
- 第五章 编码传输中的码率控制
- 分享视频剪辑技巧,视频尺寸和格式修改为相同
- 献给java初学者,非常适合新手练习的Java项目
- 美团点评2018春招后台开发方向编程题 - 题解
- 常用软件(Android)
- 一个屌丝程序猿的人生(一百)
- 星钻VIP已经来了,银河VIP还会远吗?
热门文章
- 如何把数据从阿里云迁移到华为云
- [ZT]自己制作U盘版的《电脑公司特别版》
- 弘辽科技:直通车顶级车手有多牛逼
- Java实现两个不同泛型集合之间的属性复制
- 【安卓】Android Studio 无法识别手机解决办法
- stm32F030x8xx USART2中断无法启用
- 逆水寒角色找不到服务器,《逆水寒》游戏客户端安装常见问题解决方法
- 巨杉数据库SequoiaDB特性
- php 2018-12-23转化成时间戳,php日期转时间戳,指定日期转换成时间戳
- Spring Boot对图书MARC数据处理系列之一:91marc编码中心获取MARC原始数据