因为种种原因,需要在iphone应用中实现图片查看功能,由于iphone屏幕支持多点触摸,于是是想到用“手势”来实现图片的实时缩放和移动。借鉴无所不在的internet网络资料之后,终于实现此一功能,过程如下。

一、  首先实现原图显示(不缩放)

新建MoveScaleImageView类,继承uiview。用于加载一个UIImage。它有两个主要的成员,一个UIImage对象用于指定一个内存图片,一个UIImageView控件用于显示图片。

@interface MoveScaleImageView : UIView {

UIImage* originImage;

UIImageView* imageView;

}

-(void)setImage:(UIImage*)_image;

@end

@implementation MoveScaleImageView

-(id)initWithFrame:(CGRect)frame{

if (self=[super initWithFrame:frame]) {

imageView=[[UIImageView alloc]init];

[self addSubview:imageView];

// 使图片视图支持交互和多点触摸

[imageView setUserInteractionEnabled:YES];

[imageView setMultipleTouchEnabled:YES];

}

return self;

}

-(void)dealloc{

originImage=nil;

imageView=nil;

[super dealloc];

}

-(void)setImage:(UIImage *)_image{

originImage=[[UIImage alloc]initWithCGImage:_image.CGImage];

[imageView setImage:originImage];

[imageView setFrame:CGRectMake(0, 0, _image.size.width, _image.size.height)];

// [imageView setNeedsLayout];

}

@end

最主要的就是setImage方法。

MoveScaleImageView的使用很简单。在ViewController中构造一个MoveScaleImageView,然后用一个加载了图片文件的UIImage对象设置其image成员:

UIImage* image=[UIImage imageNamed:@"df.jpg"];

MoveScaleImageView* [[MoveScaleImageView alloc]initWithFrame:

CGRectMake(0, 44, 320, 436)];

[fileContent setImage:image];

由于在这里我们没有对图片进行任何的缩放处理,对于小图片会位于屏幕的左上角,并在其他地方留下空白;对于尺寸大于屏幕的图片,则图片不能完全显示:

一、  识别手势(单点触摸与多点触摸)

要想识别手势(gesture),必须响应4个手势的通知方法(参考“iphone3开发基础教程”第13章的内容):

touchesBegan,touchesMoved,touchesEnded和touchesCancelled。

首先,我们先来考虑单点触摸情况,这比较简单一些。在单点触摸情况下,移动手指,imageView中的图片可以被拖动,这样,对于比较大的图片,我们可以通过拖动来浏览图片的各个部分,当然,对于能一次显示下全部的图片就不需要拖动了。

修改类MoveScaleImageView,在.h中增加一些声明:

@interface MoveScaleImageView : UIView {

UIImage* originImage;

UIImageView* imageView;

CGPoint gestureStartPoint;//手势开始时起点

CGFloat offsetX,offsetY;//移动时x,y方向上的偏移量

CGFloat curr_X,curr_Y;//现在截取的图片内容的原点坐标

}

-(void)setImage:(UIImage*)_image;

-(void)moveToX:(CGFloat)x ToY:(CGFloat)y;

@end

然后实现touchesBegan和touchesMoved方法。

touchesBegan方法比较简单,记录下手指第一次触摸的位置。因为任何一个拖动都必然有一个起点和终点。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

UITouch *touch=[touches anyObject];

gestureStartPoint=[touch locationInView:self];

// NSLog(@"touch:%f,%f",gestureStartPoint.x,gestureStartPoint.y);

}

然后是手指移动后回调的touchesMoved方法:

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

UITouch* touch=[touches anyObject];

CGPoint curr_point=[touch locationInView:self];

//分别计算x,和y方向上的移动

offsetX=curr_point.x-gestureStartPoint.x;

offsetY=curr_point.y-gestureStartPoint.y;

//只要在任一方向上移动的距离超过Min_offset,判定手势有效

if(fabsf(offsetX)>= min_offset||fabsf(offsetY)>=min_offset){

[self moveToX:offsetX ToY:offsetY];

gestureStartPoint.x=curr_point.x;

gestureStartPoint.y=curr_point.y;

}

}

在这里我们做了一个简单的判断,只有手指移动了超过一定像素(min_offset常量)后,才识别为拖动手势,并调用moveToX方法。在这个方法中,需要不断的更新手指移动的坐标,因为这是一个连续的过程。

-(void)moveToX:(CGFloat)x ToY:(CGFloat)y{

//计算移动后的矩形框,原点x,y坐标,矩形宽高

CGFloat destX,destY,destW,destH;

curr_X=destX=curr_X-x;

curr_Y=destY=curr_Y-y;

destW=self.frame.size.width;

destH=self.frame.size.height;

if (destX<0) {//左边界越界处理

curr_X=destX=0;

}

if (destY<0) {//上边界越界处理

curr_Y=destY=0;

}

if (destX+destW>originImage.size.width) {//右边界越界处理

curr_X=destX=originImage.size.width-destW;

}

if (destY+destH>originImage.size.height) {//右边界越界处理

curr_Y=destY=originImage.size.height-destH;

}

//创建矩形框为本fame

CGRect rect = CGRectMake(destX, destY,

self.frame.size.width, self.frame.size.height);

imageView.image=[UIImage imageWithCGImage:CGImageCreateWithImageInRect([originImageCGImage], rect)];

}

在这个方法中,我们采用了一种特殊的处理方式:截取大图片的一部分,并将截取部分显示在imageView里。我这样做的理由,是因为这是最简单、最容易的实现方式。我参考过网上的几种实现方式,发现基本上都需要使用Quartz2D API,并且实现起来要复杂得多。最终从闭路电视监控系统中得到了启发(想象一下,安保人员通过移动鼠标控制镜头移动的场景)。

我们设计了一个矩形框,用它作为模拟的镜头:

CGRect lensRect;//设置镜头的大小

同时还设计了一个全局变量用于记录图片缩放过程中的缩放倍率:

CGFloat scale;//缩放比例

当跟踪到手指移动时,让“镜头”做反向运动(为什么是反向运动?因为我们模拟的是“拖动”效果,而不是“跟踪”效果,二者是恰恰相反的)。并通过 UIImage imageWithCGImage:CGImageCreateWithImageInRect 方法,将镜头中的图像捕捉到imageView中。

这样,移动操作实际上转换成了计算矩形框的位置。当然,我们也要做好边界判断,否则当矩形框超出图片原来的范围时,会发生扭曲缩放的现象。

接下来看怎样识别多点触摸。识别单点触摸和多点触摸其实非常简单,判断touchesBegan的touches参数的count属性即可:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

if ([touches count]==2) {//识别两点触摸,并记录两点间距离

NSArray* twoTouches=[touches allObjects];

originSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self]

FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]];

}else if ([touches count]==1){

UITouch *touch=[touches anyObject];

gestureStartPoint=[touch locationInView:self];

}

}

在上面的方法中,我们根据touches的count判断是否是单点触摸并进行分别的处理。对于2点触摸,我们记录了两指间的距离并记录在全局的CGFloat变量originSpace中。spaceToPoint方法是一个简单函数,使用中学中学过的3角函数计算2点间距离:

-(CGFloat)spaceToPoint:(CGPoint)first FromPoint:(CGPoint)two{//计算两点之间的距离

float x = first.x - two.x;

float y = first.y - two.y;

return sqrt(x * x + y * y);

}

在两点触摸中,需要识别2个手势:外向捏合、内向捏合。通常前者使图像放大,而后者可使图像缩小。

在touchesMoved方法中,这样处理:

if ([touches count]==2) {

NSArray* twoTouches=[touches allObjects];

CGFloat currSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self]

FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]];

//如果先触摸一根手指,再触摸另一根手指,则触发touchesMoved方法而不是touchesBegan方法

//此时originSpace应该是0,我们要正确设置它的值为当前检测到的距离,否则可能导致0除错误

if (originSpace==0) {

originSpace=currSpace;

}

if (fabsf(currSpace-originSpace)>=min_offset) {//两指间移动距离超过min_offset,识别为手势“捏合”

CGFloat s=currSpace/originSpace;//计算缩放比例

[self scaleTo:s];

}

}else if([touches count]==1){

⋯⋯ (省略了部分代码)

}

}

先简单判断了是否为有效捏合(我们为此定义了一个常量min_offset),如果是,则计算手指有效移动长度和手势开始时的两指间距的商,以此作为缩放比例。然后调用scaleTo方法:

-(void)scaleTo:(CGFloat)x{

scale*=x;

//缩放限制:>=0.1,<=10

scale=(scale<0.1)?0.1:scale;

scale=(scale>10)?10:scale;

//重设imageView的frame

[self moveToX:0 ToY:0];

}

这里,为防止用户无限制的对图像进行“捏合”操作,我们限制了scale的值在0.1-10之间(当然你可以将这个阀值定义为常量)。然后调用了一个原地的移动操作,即前面的moveTo方法。然而为支持缩放下的图片移动,这个方法被我们更改了:

-(void)moveToX:(CGFloat)x ToY:(CGFloat)y{

CGPoint point=CGPointMake(x, y);

//重设镜头

[self resetLens:point];

imageView.image=[UIImage imageWithCGImage:CGImageCreateWithImageInRect([originImageCGImage], lensRect)];

[imageView setFrame:CGRectMake(0, 0, lensRect.size.width*scale, vlensRect.size.height*scale)];

}

其中更多的代码被我们移到了另一个方法resetLens中:

-(void)resetLens:(CGPoint)point{//设置镜头大小和位置

CGFloat x,y,width,height;

//===========镜头初始大小=========

width=self.frame.size.width/scale;

height=self.frame.size.height/scale;

//===========调整镜大小不得超过图像实际大小==========

if(width>originImage.size.width){

width=originImage.size.width;

}

if (height>originImage.size.height) {

height=originImage.size.height;

}

//计算镜头移动的位置(等比缩放)

x=lensRect.origin.x-point.x/scale;

y=lensRect.origin.y-point.y/scale;

//左边界越界处理

x=(x<0)?0:x;

//上边界越界处理

y=(y<0)?0:y;

//右边界越界

x=(x+width>originImage.size.width)?originImage.size.width-width:x;

//下边界越界处理

y=(y+height>originImage.size.height)?originImage.size.height-height:y;

//镜头等比缩放

lensRect=CGRectMake(x, y, width, height);

}

这些代码跟原来moveToX方法中的代码有些许的不同,主要是增加了对scale变量的引入,因为在缩放模式下,镜头的移动都是被scale系数缩放过的。通代码中的注释,我们不难理解整个代码。

这样,大图片经过“捏合”操作可以在屏幕上完全显示出来(上面原来基本看不清楚的第2张图片现在是一台苹果电脑):

当然,把小图片“捏合”放大成大图片也是可以的。此外通过手指的移动,能查看图片的不同部分。

 
 
(二)
 

在这个方法中,我们采用了一种特殊的处理方式:截取大图片的一部分,并将截取部分显示在imageView里。我这样做的理由,是因为这是最简单、最容易的实现方式。我参考过网上的几种实现方式,发现基本上都需要使用Quartz2D API,并且实现起来要复杂得多。最终从闭路电视监控系统中得到了启发(想象一下,安保人员通过移动鼠标控制镜头移动的场景)。

我们设计了一个矩形框,用它作为模拟的镜头:

CGRect lensRect;//设置镜头的大小

同时还设计了一个全局变量用于记录图片缩放过程中的缩放倍率:

CGFloat scale;//缩放比例

当跟踪到手指移动时,让“镜头”做反向运动(为什么是反向运动?因为我们模拟的是“拖动”效果,而不是“跟踪”效果,二者是恰恰相反的)。并通过 UIImage imageWithCGImage:CGImageCreateWithImageInRect 方法,将镜头中的图像捕捉到imageView中。

这样,移动操作实际上转换成了计算矩形框的位置。当然,我们也要做好边界判断,否则当矩形框超出图片原来的范围时,会发生扭曲缩放的现象。

接下来看怎样识别多点触摸。识别单点触摸和多点触摸其实非常简单,判断touchesBegan的touches参数的count属性即可:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

if ([touches count]==2) {//识别两点触摸,并记录两点间距离

NSArray* twoTouches=[touches allObjects];

originSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self]

FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]];

}else if ([touches count]==1){

UITouch *touch=[touches anyObject];

gestureStartPoint=[touch locationInView:self];

}

}

在上面的方法中,我们根据touches的count判断是否是单点触摸并进行分别的处理。对于2点触摸,我们记录了两指间的距离并记录在全局的CGFloat变量originSpace中。spaceToPoint方法是一个简单函数,使用中学中学过的3角函数计算2点间距离:

-(CGFloat)spaceToPoint:(CGPoint)first FromPoint:(CGPoint)two{//计算两点之间的距离

float x = first.x - two.x;

float y = first.y - two.y;

return sqrt(x * x + y * y);

}

在两点触摸中,需要识别2个手势:外向捏合、内向捏合。通常前者使图像放大,而后者可使图像缩小。

在touchesMoved方法中,这样处理:

if ([touches count]==2) {

NSArray* twoTouches=[touches allObjects];

CGFloat currSpace=[self spaceToPoint:[[twoTouches objectAtIndex:0] locationInView:self]

FromPoint:[[twoTouches objectAtIndex:1]locationInView:self]];

//如果先触摸一根手指,再触摸另一根手指,则触发touchesMoved方法而不是touchesBegan方法

//此时originSpace应该是0,我们要正确设置它的值为当前检测到的距离,否则可能导致0除错误

if (originSpace==0) {

originSpace=currSpace;

}

if (fabsf(currSpace-originSpace)>=min_offset) {//两指间移动距离超过min_offset,识别为手势“捏合”

CGFloat s=currSpace/originSpace;//计算缩放比例

[self scaleTo:s];

}

}else if([touches count]==1){

⋯⋯ (省略了部分代码)

}

}

先简单判断了是否为有效捏合(我们为此定义了一个常量min_offset),如果是,则计算手指有效移动长度和手势开始时的两指间距的商,以此作为缩放比例。然后调用scaleTo方法:

-(void)scaleTo:(CGFloat)x{

scale*=x;

//缩放限制:>=0.1,<=10

scale=(scale<0.1)?0.1:scale;

scale=(scale>10)?10:scale;

//重设imageView的frame

[self moveToX:0 ToY:0];

}

这里,为防止用户无限制的对图像进行“捏合”操作,我们限制了scale的值在0.1-10之间(当然你可以将这个阀值定义为常量)。然后调用了一个原地的移动操作,即前面的moveTo方法。然而为支持缩放下的图片移动,这个方法被我们更改了:

-(void)moveToX:(CGFloat)x ToY:(CGFloat)y{

CGPoint point=CGPointMake(x, y);

//重设镜头

[self resetLens:point];

imageView.image=[UIImage imageWithCGImage:CGImageCreateWithImageInRect([originImage CGImage], lensRect)];

[imageView setFrame:CGRectMake(0, 0, lensRect.size.width*scale, vlensRect.size.height*scale)];

}

其中更多的代码被我们移到了另一个方法resetLens中:

-(void)resetLens:(CGPoint)point{//设置镜头大小和位置

CGFloat x,y,width,height;

//===========镜头初始大小=========

width=self.frame.size.width/scale;

height=self.frame.size.height/scale;

//===========调整镜大小不得超过图像实际大小==========

if(width>originImage.size.width){

width=originImage.size.width;

}

if (height>originImage.size.height) {

height=originImage.size.height;

}

//计算镜头移动的位置(等比缩放)

x=lensRect.origin.x-point.x/scale;

y=lensRect.origin.y-point.y/scale;

//左边界越界处理

x=(x<0)?0:x;

//上边界越界处理

y=(y<0)?0:y;

//右边界越界

x=(x+width>originImage.size.width)?originImage.size.width-width:x;

//下边界越界处理

y=(y+height>originImage.size.height)?originImage.size.height-height:y;

//镜头等比缩放

lensRect=CGRectMake(x, y, width, height);

}

这些代码跟原来moveToX方法中的代码有些许的不同,主要是增加了对scale变量的引入,因为在缩放模式下,镜头的移动都是被scale系数缩放过的。通代码中的注释,我们不难理解整个代码。

这样,大图片经过“捏合”操作可以在屏幕上完全显示出来(上面原来基本看不清楚的第2张图片现在是一台苹果电脑):

在ios开发中,肯定会碰到需要截取部分图片的情况。

最终的效果类似这样:

先看最原始的示例,显示完整的图片

写了个最简单的读取图片并显示的代码,打算以此为开始,逐渐实现截取部分图片的功能。

代码主要是,在控制器代码中:

- (void)loadView { 
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlide]; 
    UIImage *image=[UIImage imageNamed:@"1.jpg"]; 
    
    UIImageView *contentView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [contentView setImage:image]; 
    
    self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [self.view addSubview:contentView]; 
}

另外,应该有一个名为1.jpg的768×1024的图片(我这里是iPad)。

截取整个图片

可以认为截取整个图片是截取部分图片的一个特例。对ios不熟嘛,因此打算很谨慎的推进。截取整个图片可以减少中间的复杂性。

根据API,摸索着写了一个示例,效果出乎意料:

代码:

- (void)loadView { 
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlide]; 
    UIImage *image=[UIImage imageNamed:@"1.jpg"]; 
    
    UIImageView *contentView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    //[contentView setImage:image]; 
    
    CGRect rect = CGRectMake(0, 0, 768, 1024);//创建矩形框 
    UIGraphicsBeginImageContext(rect.size);//根据size大小创建一个基于位图的图形上下文 
    CGContextRef currentContext = UIGraphicsGetCurrentContext();//获取当前quartz 2d绘图环境 
    CGContextClipToRect( currentContext, rect);//设置当前绘图环境到矩形框 
    
    CGContextDrawImage(currentContext, rect, image.CGImage);//绘图 
    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();//获得图片 
    UIGraphicsEndImageContext();//从当前堆栈中删除quartz 2d绘图环境 
    
    contentView.image=cropped; 
    
    self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [self.view addSubview:contentView];

[cropped release]; 
}

这个代码说明了两点:

  • 好的方面:说明我的代码起作用了,确实截取了所需的图形
  • 坏的方面:图形是颠倒的,而且是镜像的。

问题应该出在坐标系上。下面画了一个quartz 2d的坐标系,坐标原点在左下角:

因此以这个坐标系取图形,就会有转向180°的效果。

其实如果是对图片的缩放,而不是剪切部分图片内容,这样写就可以了:

- (void)loadView { 
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlide]; 
    UIImage *image=[UIImage imageNamed:@"1.jpg"]; 
    
    //[contentView setImage:image]; 
    
    CGRect rect = CGRectMake(0, 0, 384, 512);//创建矩形框 
    UIGraphicsBeginImageContext(rect.size);//根据size大小创建一个基于位图的图形上下文 
    CGContextRef currentContext = UIGraphicsGetCurrentContext();//获取当前quartz 2d绘图环境 
    CGContextClipToRect(currentContext, rect);//设置当前绘图环境到矩形框 
    
    //CGContextRotateCTM(currentContext, 50); 
    
    //CGContextDrawImage(currentContext, rect, image.CGImage);//绘图 
    
    [image drawInRect:rect]; 
    
    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();//获得图片 
    UIGraphicsEndImageContext();//从当前堆栈中删除quartz 2d绘图环境 
    
    UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect]; 
    contentView.image=cropped; 
    
    self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [self.view addSubview:contentView];

[cropped release]; 
}

效果类似这样:

这个方法可以帮助我们在后续开发中实现缩略图。但是不符合现在的需求。

于是想了下面的基本思路:

这样,需要一个能旋转和向下移动的API。ios提供了C++界面的函数调用:

  • CGContextRotateCTM,实现角度的转换
  • CGContextTranslateCTM,可以重新设置坐标系原点,平移坐标系和移动图片是等效的

代码:

- (void)loadView { 
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlide]; 
    UIImage *image=[UIImage imageNamed:@"1.jpg"]; 
    
    //[contentView setImage:image]; 
    
    CGRect rect = CGRectMake(0, 0, 384, 512);//创建矩形框 
    UIGraphicsBeginImageContext(rect.size);//根据size大小创建一个基于位图的图形上下文 
    CGContextRef currentContext = UIGraphicsGetCurrentContext();//获取当前quartz 2d绘图环境 
    CGContextClipToRect(currentContext, rect);//设置当前绘图环境到矩形框 
    
    CGContextRotateCTM(currentContext, M_PI); 
    CGContextTranslateCTM(currentContext, -rect.size.width, -rect.size.height); 
    
    CGContextDrawImage(currentContext, rect, image.CGImage);//绘图 
    
    //[image drawInRect:rect]; 
    
    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();//获得图片 
    UIGraphicsEndImageContext();//从当前堆栈中删除quartz 2d绘图环境 
    
    UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect]; 
    contentView.image=cropped; 
    
    self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [self.view addSubview:contentView];

[cropped release]; 
}

这个结果还有缺陷,可以看到图片是正立的了,但是图片反转了,是个镜像。

解决办法也有,不过不是操作图片了,而是操作图片所在的视图。思路是把视图看作一个位图的矩阵,对它做矩阵变换运算,使视图做镜像反转。写法很简单:

- (void)loadView { 
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlide]; 
    UIImage *image=[UIImage imageNamed:@"1.jpg"]; 
    
    //[contentView setImage:image]; 
    
    CGRect rect = CGRectMake(0, 0, 384, 512);//创建矩形框 
    UIGraphicsBeginImageContext(rect.size);//根据size大小创建一个基于位图的图形上下文 
    CGContextRef currentContext = UIGraphicsGetCurrentContext();//获取当前quartz 2d绘图环境 
    CGContextClipToRect(currentContext, rect);//设置当前绘图环境到矩形框 
    
    
    CGContextRotateCTM(currentContext, M_PI); 
    CGContextTranslateCTM(currentContext, -rect.size.width, -rect.size.height); 
    //CGContextTranslateCTM(currentContext,0.0,200.0); 
    
    CGContextDrawImage(currentContext, rect, image.CGImage);//绘图 
    
    //[image drawInRect:rect]; 
    
    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();//获得图片 
    UIGraphicsEndImageContext();//从当前堆栈中删除quartz 2d绘图环境 
    
        
    UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect]; 
    contentView.image=cropped; 
    
    contentView.transform = CGAffineTransformIdentity; 
    contentView.transform = CGAffineTransformMakeScale(-1.0, 1.0);

self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [self.view addSubview:contentView];

[cropped release]; 
}

这里的转换因子,一个是针对x轴的,一个是针对y轴的。终于可以产生这样的效果了:

这里参考了这个文档:

http://macdevcenter.com/pub/a/mac/2004/11/02/quartz.html

虽然是很古老的文章了,但是说的很清楚。另外,方法名称已经发生变化,需要注意。

截取部分图片

截取部分图片,比如:

截取左边人像部分。

实现后的代码,效果是这样的:

如何实现的呢,这时候才发现,其实根本不需要上面那些转换,如果不使用quartz 2d的话,截取部分图片这么简单:

- (void)loadView { 
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlide]; 
    UIImage *image=[UIImage imageNamed:@"1.jpg"]; 
    
    
    CGRect rect = CGRectMake(60, 80, 331, 353);//创建矩形框 
    UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect]; 
    contentView.image=[UIImage imageWithCGImage:CGImageCreateWithImageInRect([image CGImage], rect)]; 
    
    self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    [self.view addSubview:contentView]; 
    
    [image release]; 
}

虽然编写代码的过程是曲折的,但是摸到很多有用的东西,都是以后要用到的。

 
 
我昨天做好了,可以剪切图片,但是旋转的话,图片切不准~求高手解答~

对图片进行处理(得到某张图片的一部分)可一用以下代码:

UIImage *image = [UIImage imageNamed:filename];

CGImageRef imageRef = image.CGImage;

CGRect rect = CGRectMake(origin.x, origin.y ,size.width, size.height);

CGImageRef imageRefRect = CGImageCreateWithImageInRect(imageRef, rect);

UIImage *imageRect = [[UIImage alloc] initWithCGImage:imageRefRect];

把当前的视图作为照片保存到相册中去:

#import <QuartzCore/QuartzCore.h>

UIGraphicsBeginImageContext(currentView.bounds.size);     //currentView 当前的view

[currentView.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);

使UIimageView的图像旋转:

float rotateAngle = M_PI;

CGAffineTransform transform =CGAffineTransformMakeRotation(rotateAngle);

imageView.transform = transform;

 
前阵子为一个帖子做了个类似的,没有加旋转
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint currentPoint = [touch locationInView:self]; CGRect rect = CGRectMake(currentPoint.x+3, currentPoint.y+3, v.bounds.size.width, v.bounds.size.height); v.frame = rect; v.image = [self createRectImage:pubImg rect:rect]; [v setNeedsDisplay]; } -(UIImage*) createRectImage:(UIImage*)image rect:(CGRect) rect { // the size of CGContextRefCGImageRef imageRef=CGImageCreateWithImageInRect([image CGImage],rect); UIImage* elementImage=[UIImage imageWithCGImage:imageRef]; return elementImage; }
 
 
 
 
 
本文转载至  http://blog.csdn.net/yanfangjin/article/details/7465687
 

ios学习--结合UIImageView实现图片的移动和缩放的更多相关文章

  1. iOS学习笔记之异步图片下载

    写在前面 在iOS开发中,无论是在UITableView还是在UICollectionView中,通过网络获取图片设置到cell上是较为常见的需求.尽管有很多现存的第三方库可以将下载和缓存功能都封装好 ...

  2. ios学习-制作一个浏览图片的Demo

    一.项目要求:制作一个浏览图片的Demo,要求包含夜间模式,以及改变图片大小,能够显示不同的图片描述 二.开发步骤: 1.在storyboard上添加一个空白的View,然后添加”设置“按钮,添加im ...

  3. [置顶] iOS学习笔记47——图片异步加载之EGOImageLoading

    上次在<iOS学习笔记46——图片异步加载之SDWebImage>中介绍过一个开源的图片异步加载库,今天来介绍另外一个功能类似的EGOImageLoading,看名字知道,之前的一篇学习笔 ...

  4. iOS学习笔记31-从图册获取图片和视频

    一.从图册中获取本地图片和视频 从图册中获取文件,我们使用的是UIImagePickerController,这个类我们在之前的摄像头中使用过,这里是链接:iOS学习笔记27-摄像头,这里我们使用的是 ...

  5. iOS学习-压缩图片(改变图片的宽高)

    压缩图片,图片的大小与我们期望的宽高不一致时,我们可以将其处理为我们想要的宽高. 传入想要修改的图片,以及新的尺寸 -(UIImage*)imageWithImage:(UIImage*)image ...

  6. ios 从网络上获取图片并在UIImageView中显示

    ios 从网络上获取图片   -(UIImage *) getImageFromURL:(NSString *)fileURL { NSLog(@"执行图片下载函数"); UIIm ...

  7. ios 学习线路(图片)(摘录)

    iOS学习路线

  8. iOS学习资料整理

    视频教程(英文) 视频 简介 Developing iOS 7 Apps for iPhone and iPad 斯坦福开放教程之一, 课程主要讲解了一些 iOS 开发工具和 API 以及 iOS S ...

  9. iOS 学习

    iOS 学习资料 (适合初学者) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解 ...

随机推荐

  1. HTML5学习笔记 Geolocation(地理定位)

    HTML5 Geolocation(地理定位)用于定位用户的位置. 定位用户的位置 html5 Geolocation API用于获得用户的地理位置 鉴于该特性可能低侵犯用户的隐私,除非用户同意,否则 ...

  2. DirectX.DirectSound声音播放资料

    参考:https://msdn.microsoft.com/en-us/library/windows/desktop/bb318665(v=vs.85).aspx Microsoft DirectS ...

  3. python基础之Event对象、队列和多进程基础

    Event对象 用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象 event对象默认为假(Flase),即遇到event对象在等待就阻塞线程 ...

  4. 统计时间段内周分类SQL语句

    declare @datefrom as datetime,@dateto as datetime set @datefrom='2015-04-12' set @dateto='2015-08-13 ...

  5. laravel的cookie操作

    前提你的整个http流程一定要走完,页就是必须走到view()或Response,你写到中间中断调试,cookie是设置不上去的......(坑~~) 读取: $value = Cookie::get ...

  6. MS SQL表字段自增相关的脚本

    --查询表是否有自增字段 SELECT OBJECTPROPERTY(OBJECT_ID('[表名]'), 'TableHasIdentity') --查询表的自增字段 SELECT COLUMN_N ...

  7. Json映射为Map,避免定义过多pojo类

    我们在开发过程中经常会遇到解析Json字符串的情况,这时候采用开源工具可以快速将json字符串映射为pojo对象.而在某些业务场景中,往往为了获得json字符串中某个属性的值而不得不定义一个pojo类 ...

  8. hdu 2066 一个人的旅行(dijkstra)

    一个人的旅行 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  9. 源码编译安装git

    debian上的git版本才2.1有点低了,为了安装最新版的2.11,我决定从源码编译安装一下. 预备工作: 1.安装编译工具.apt install -y  build-essential 2.安装 ...

  10. (oneway void) release中oneway的意思

    oneway is used with the distributed objects API, which allows use of objective-c objects between dif ...