结合UIImageView实现图片的移动和缩放

因为种种原因,需要在应用中实现图片查看功能,由于屏幕支持多点触摸,于是是想到用“手势”来实现图片的实时缩放和移动 。借鉴无所不在的网络资料之后,终于实现此一功能,过程如下 。
为方便大家下载,示例代码已上传到资源:
一、首先实现原图显示(不缩放)
新建类,继承 。用于加载一个 。它有两个主要的成员,一个对象用于指定一个内存图片,一个控件用于显示图片 。
@: {
* ;
* ;
-(void):(*);
@end
@
-(id):()frame{
if (self=[:frame]) {
=[[]init];
[:];
// 使图片视图支持交互和多点触摸
[:YES];
[:YES];
;
-(void){
=nil;
=nil;
[];
-(void):( *){
=[[]:.];
[:];
[:(0, 0, .size.width, .size.)];
// [ ];
@end
最主要的就是方法 。
的使用很简单 。在中构造一个,然后用一个加载了图片文件的对象设置其image成员:
* image=[:@"df.jpg"];
* [[loc]:
(0, 44, 320, 436)];
[:image];
由于在这里我们没有对图片进行任何的缩放处理,对于小图片会位于屏幕的左上角,并在其他地方留下空白;对于尺寸大于屏幕的图片,则图片不能完全显示:
一、识别手势(单点触摸与多点触摸)
要想识别手势(),必须响应4个手势的通知方法(参考“开发基础教程”第13章的内容):
,,和 。
首先,我们先来考虑单点触摸情况,这比较简单一些 。在单点触摸情况下,移动手指,中的图片可以被拖动,这样,对于比较大的图片,我们可以通过拖动来浏览图片的各个部分,当然,对于能一次显示下全部的图片就不需要拖动了 。
修改类,在.h中增加一些声明:
@: {
* ;
* ;
oint;//手势开始时起点

结合UIImageView实现图片的移动和缩放

文章插图
,;//移动时x,y方向上的偏移量
,;//现在截取的图片内容的原点坐标
-(void):(*);
-(void):()x ToY:()y;
@end
然后实现和方法 。
方法比较简单,记录下手指第一次触摸的位置 。因为任何一个拖动都必然有一个起点和终点 。
-(void):(NSSet *) :( *)event{
*touch=[ ];
=[touch :self];
// NSLog(@"touch:%f,%f",.x,.y);
然后是手指移动后回调的方法:
-(void):(NSSet *) :( *)event{
* touch=[ ];
=[touch :self];
//分别计算x,和y方向上的移动
=.x-.x;
=.y-.y;
//只要在任一方向上移动的距离超过,判定手势有效
if(fabsf()>= ||fabsf()>=){
[::];
.x=.x;
.y=.y;
在这里我们做了一个简单的判断,只有手指移动了超过一定像素(常量)后,才识别为拖动手势,并调用方法 。在这个方法中,需要不断的更新手指移动的坐标,因为这是一个连续的过程 。
-(void):()x ToY:()y{
//计算移动后的矩形框,原点x,y坐标,矩形宽高
destX,destY,destW,destH;
=destX=-x;
=destY=-y;
destW=self.frame.size.width;
destH=self.frame.size.;
if (.size.) {//右边界越界处理
=destY=.size.-destH;
//创建矩形框为本fame
rect = (destX, destY,
self.frame.size.width, self.frame.size.);
.image=[age:([], rect)];
在这个方法中,我们采用了一种特殊的处理方式:截取大图片的一部分,并将截取部分显示在里 。我这样做的理由,是因为这是最简单、最容易的实现方式 。我参考过网上的几种实现方式,发现基本上都需要使用,并且实现起来要复杂得多 。最终从闭路电视监控系统中得到了启发(想象一下,安保人员通过移动鼠标控制镜头移动的场景) 。
我们设计了一个矩形框,用它作为模拟的镜头:
;//设置镜头的大小
同时还设计了一个全局变量用于记录图片缩放过程中的缩放倍率:
;//缩放比例
当跟踪到手指移动时,让“镜头”做反向运动(为什么是反向运动?因为我们模拟的是“拖动”效果,而不是“跟踪”效果,二者是恰恰相反的) 。并通过 age: 方法,将镜头中的图像捕捉到中 。
这样,移动操作实际上转换成了计算矩形框的位置 。当然,我们也要做好边界判断,否则当矩形框超出图片原来的范围时,会发生扭曲缩放的现象 。
接下来看怎样识别多点触摸 。识别单点触摸和多点触摸其实非常简单,判断的参数的count属性即可:
-(void):(NSSet *) :( *)event{
if ([ count]==2) {//识别两点触摸,并记录两点间距离
* =[ ];
=[:[[ :0] :self]
:[[ :1]:self]];
} ([ count]==1){
*touch=[ ];
=[:self];
在上面的方法中,我们根据的count判断是否是单点触摸并进行分别的处理 。对于2点触摸,我们记录了两指间的距离并记录在全局的变量中 。方法是一个简单函数,使用中学中学过的3角函数计算2点间距离:
-():()first :()two{//计算两点之间的距离
float x = first.x - two.x;
float y = first.y - two.y;
(x * x + y * y);
在两点触摸中,需要识别2个手势:外向捏合、内向捏合 。通常前者使图像放大,而后者可使图像缩小 。
在方法中,这样处理:
if ([ count]==2) {
* =[ ];
=[:[[ :0] :self]
:[[ :1]:self]];
//如果先触摸一根手指,再触摸另一根手指,则触发方法而不是方法
//此时应该是0,我们要正确设置它的值为当前检测到的距离,否则可能导致0除错误
if (==0) {
【结合UIImageView实现图片的移动和缩放】=;
if (fabsf(-)>=) {//两指间移动距离超过,识别为手势“捏合”
s=/;//计算缩放比例
[:s];
}([ count]==1){
??(省略了部分代码)
先简单判断了是否为有效捏合(我们为此定义了一个常量),如果是,则计算手指有效移动长度和手势开始时的两指间距的商,以此作为缩放比例 。然后调用方法:
-(void):()x{
scale*=x;
//缩放限制:>=0.1,.size.width){
width=.size.width;
if (>.size.) {
=.size.;
//计算镜头移动的位置(等比缩放)
x=..x-point.x/scale;
y=..y-point.y/scale;
//左边界越界处理
x=(.size.)?.size.-:y;
//镜头等比缩放
=(x, y, width, );
这些代码跟原来方法中的代码有些许的不同,主要是增加了对scale变量的引入,因为在缩放模式下,镜头的移动都是被scale系数缩放过的 。通代码中的注释,我们不难理解整个代码 。
这样,大图片经过“捏合”操作可以在屏幕上完全显示出来(上面原来基本看不清楚的第2张图片现在是一台苹果电脑):
当然,把小图片“捏合”放大成大图片也是可以的 。此外通过手指的移动,能查看图片的不同部分 。
再分享一下我老师大神的人工智能教程吧 。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!