因為種種原因,需要在iphone應(yīng)用中實現(xiàn)圖片查看功能,由于iphone屏幕支持多點觸摸,于是是想到用“手勢”來實現(xiàn)圖片的實時縮放和移動。借鑒無所不在的internet網(wǎng)絡(luò)資料之后,終于實現(xiàn)此一功能,過程如下。一、首先實現(xiàn)原圖顯示(不縮放)新建MoveScaleImageView類,繼承uiview。用于加載一個UIImage。它有兩個主要的成員,一個UIImage對象用于指定一個內(nèi)存圖片,一個UIImageView" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

結(jié)合UIImageView實現(xiàn)圖片的移動和縮放

系統(tǒng) 1879 0

<!--StartFragment-->

因為種種原因,需要在 iphone應(yīng)用中實現(xiàn)圖片查看功能,由于iphone屏幕支持多點觸摸,于是是想到用“手勢”來實現(xiàn)圖片的實時縮放和移動。借鑒無所不在的internet網(wǎng)絡(luò)資料之后,終于實現(xiàn)此一功能,過程如下。

一、 首先實現(xiàn)原圖顯示(不縮放)

新建 MoveScaleImageView類,繼承uiview。用于加載一個UIImage。它有兩個主要的成員,一個UIImage對象用于指定一個內(nèi)存圖片,一個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中構(gòu)造一個MoveScaleImageView,然后用一個加載了圖片文件的UIImage對象設(shè)置其image成員:

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

MoveScaleImageView* [[ MoveScaleImageView alloc ] initWithFrame :

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

[ fileContent setImage :image];

由于在這里我們沒有對圖片進(jìn)行任何的縮放處理,對于小圖片會位于屏幕的左上角,并在其他地方留下空白;對于尺寸大于屏幕的圖片,則圖片不能完全顯示:

結(jié)合UIImageView實現(xiàn)圖片的移動和縮放 結(jié)合UIImageView實現(xiàn)圖片的移動和縮放

<!--StartFragment-->

一、 識別手勢(單點觸摸與多點觸摸)

要想識別手勢( gesture),必須響應(yīng)4個手勢的通知方法(參考“iphone3開發(fā)基礎(chǔ)教程”第13章的內(nèi)容):

touchesBegan,touchesMoved,touchesEnded和touchesCancelled。

首先,我們先來考慮單點觸摸情況,這比較簡單一些。在單點觸摸情況下,移動手指, imageView中的圖片可以被拖動,這樣,對于比較大的圖片,我們可以通過拖動來瀏覽圖片的各個部分,當(dāng)然,對于能一次顯示下全部的圖片就不需要拖動了。

修改類 MoveScaleImageView,在.h中增加一些聲明:

@interface MoveScaleImageView : UIView {

UIImage * originImage ;

UIImageView * imageView ;

CGPoint gestureStartPoint ; // 手勢開始時起點

CGFloat offsetX , offsetY ; // 移動時 x,y 方向上的偏移量

CGFloat curr_X , curr_Y ; // 現(xiàn)在截取的圖片內(nèi)容的原點坐標(biāo)

}

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

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

@end

然后實現(xiàn) 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);

}

然后是手指移動后回調(diào)的 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常量)后,才識別為拖動手勢,并調(diào)用moveToX方法。在這個方法中,需要不斷的更新手指移動的坐標(biāo),因為這是一個連續(xù)的過程。

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

// 計算移動后的矩形框,原點 x,y 坐標(biāo),矩形寬高

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;

}

// 創(chuàng)建矩形框為本 fame

CGRect rect = CGRectMake (destX, destY,

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

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

}

在這個方法中,我們采用了一種特殊的處理方式:截取大圖片的一部分,并將截取部分顯示在 imageView里。我這樣做的理由,是因為這是最簡單、最容易的實現(xiàn)方式。我參考過網(wǎng)上的幾種實現(xiàn)方式,發(fā)現(xiàn)基本上都需要使用Quartz2D API,并且實現(xiàn)起來要復(fù)雜得多。最終從閉路電視監(jiān)控系統(tǒng)中得到了啟發(fā)(想象一下,安保人員通過移動鼠標(biāo)控制鏡頭移動的場景)。

我們設(shè)計了一個矩形框,用它作為模擬的鏡頭:

CGRect lensRect ; // 設(shè)置鏡頭的大小

同時還設(shè)計了一個全局變量用于記錄圖片縮放過程中的縮放倍率:

CGFloat scale ; // 縮放比例

當(dāng)跟蹤到手指移動時,讓“鏡頭”做反向運動(為什么是反向運動?因為我們模擬的是“拖動”效果,而不是“跟蹤”效果,二者是恰恰相反的)。并通過 UIImage imageWithCGImage : CGImageCreateWithImageInRect 方法,將鏡頭中的圖像捕捉到imageView中。

這樣,移動操作實際上轉(zhuǎn)換成了計算矩形框的位置。當(dāng)然,我們也要做好邊界判斷,否則當(dāng)矩形框超出圖片原來的范圍時,會發(fā)生扭曲縮放的現(xiàn)象。

接下來看怎樣識別多點觸摸。識別單點觸摸和多點觸摸其實非常簡單,判斷 touchesBegan的touches參數(shù)的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 ];

}

}

在上面的方法中,我們根據(jù) touches的count判斷是否是單點觸摸并進(jìn)行分別的處理。對于2點觸摸,我們記錄了兩指間的距離并記錄在全局的CGFloat變量originSpace中。spaceToPoint方法是一個簡單函數(shù),使用中學(xué)中學(xué)過的3角函數(shù)計算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個手勢:外向捏合、內(nèi)向捏合。通常前者使圖像放大,而后者可使圖像縮小。

touchesMoved方法中,這樣處理:

if ([touches count ]== 2 ) {

NSArray * twoTouches=[touches allObjects ];

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

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

// 如果先觸摸一根手指,再觸摸另一根手指,則觸發(fā) touchesMoved 方法而不是 touchesBegan 方法

// 此時 originSpace 應(yīng)該是 0 ,我們要正確設(shè)置它的值為當(dāng)前檢測到的距離,否則可能導(dǎo)致 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 ){

??(省略了部分代碼)

}

}

先簡單判斷了是否為有效捏合(我們?yōu)榇硕x了一個常量 min_offset),如果是,則計算手指有效移動長度和手勢開始時的兩指間距的商,以此作為縮放比例。然后調(diào)用scaleTo方法:

-( void )scaleTo:( CGFloat )x{

scale *=x;

// 縮放限制: > 0.1 <=10

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

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

// 重設(shè) imageView frame

[ self moveToX : 0 ToY : 0 ];

}

這里,為防止用戶無限制的對圖像進(jìn)行“捏合”操作,我們限制了 scale的值在0.1-10之間(當(dāng)然你可以將這個閥值定義為常量)。然后調(diào)用了一個原地的移動操作,即前面的moveTo方法。然而為支持縮放下的圖片移動,這個方法被我們更改了:

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

CGPoint point= CGPointMake (x, y);

// 重設(shè)鏡頭

[ 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{ // 設(shè)置鏡頭大小和位置

CGFloat x,y,width,height;

//=========== 鏡頭初始大小 =========

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

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

//=========== 調(diào)整鏡大小不得超過圖像實際大小 ==========

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系數(shù)縮放過的。通代碼中的注釋,我們不難理解整個代碼。

這樣,大圖片經(jīng)過“捏合”操作可以在屏幕上完全顯示出來(上面原來基本看不清楚的第 2張圖片現(xiàn)在是一臺蘋果電腦):

結(jié)合UIImageView實現(xiàn)圖片的移動和縮放

<!--StartFragment-->

當(dāng)然,把小圖片“捏合”放大成大圖片也是可以的。此外 通過手指的移動,能查看圖片的不同部分。

<!--EndFragment-->

<!--EndFragment-->

結(jié)合UIImageView實現(xiàn)圖片的移動和縮放


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久草视频免费播放 | 久操综合 | 欧美色插 | 亚洲国产一区二区三区在线观看 | 男人草女人的视频 | 日韩高清一区二区 | 九天玄帝诀免费完整观看 | 精品中文字幕久久久久久 | 日韩视频一区二区在线观看 | 国产精品三 | 激情一区二区三区 | 一级欧美毛片成人免费视频 | 国产不卡在线观看视频 | 一本大道香蕉高清久久 | 国产成人爱片免费观看视频 | 日本特级全黄一级毛片 | 最新精品国产 | 久久久久在线观看 | 亚洲在线网站 | 香蕉亚洲欧洲在线一区 | 精品亚洲欧美中文字幕在线看 | 欧美大片a一级毛片视频 | 国产爆操 | 888午夜不卡理论久久 | 中文字幕日韩亚洲 | 成在线人永久免费播放视频 | 成人免费xxx色视频 成人免费播放视频777777 | 日韩免费高清一级毛片在线 | 国产综合成人亚洲区 | 四虎在线永久视频观看 | 日韩亚洲欧洲在线rrrr片 | 狠狠做深爱婷婷久久一区 | 97在线视频99播放 | 久久久噜久噜久久gif动图 | 神马影院我不卡888 神马影院我不卡手机 | 欧美亚洲国产精品 | 色播影院性播影院私人影吧 | 99玖玖| 久久久久久国产精品免费免 | 亚洲精品久久久久综合中文字幕 | 亚洲日本欧美在线 |