GitHub地址 https://github.com/JerryWanXuJie/XJAlbum
圖片瀏覽器主要通過 UIScrollView 實現 在一個大的ScollView里面套 n個ScollView
UIScrollView里主要是有兩個屬性,contentSize和contentoffset , contentSize 是設定UIScrollView的可交互的大小,contentoffset偏移量
設置第一層 UIScollView 主要是設置 contentSize 和 contentoffset , contentSize 是根據圖片的個數來設定,contentoffset根據當前圖片編號設定
wholeScoll = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, myScreenWidth, myScreenHeight)]; wholeScoll.contentOffset = CGPointMake(wholeScoll.frame.size.width*mcurpage, 0);
wholeScoll.contentSize = CGSizeMake(myScreenWidth*mImgLocationArr.count, myScreenHeight);
// 主要代碼是通過for 循環添加第二層UIScrollView
for (int i = 0; i<mImgLocationArr.count; i++) {
//設置 imageview
UIImageView * imgview = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, myScreenWidth, myScreenHeight)];
imgview.contentMode = UIViewContentModeScaleAspectFit;
//設置 scrollview
UIScrollView * singleview = [[UIScrollView alloc]initWithFrame:CGRectMake(myScreenWidth*i,0,myScreenWidth, myScreenHeight)];
[wholeScoll addSubview:singleview];
[singleview addSubview:imgview];
// 添加手勢
[self addGestureRecognizer];
}
圖片瀏覽器中圖片可以左右滑動,可以雙擊放大,可以手勢捏合放大縮小
圖片瀏覽器中主要有三種手勢分別是單擊 singleTap 雙擊doubleTap 捏合 pinchGesture 和UIScrollView自帶的滑動手勢
singleTap 手勢主要是返回上一頁面,如果觸發singleTap的時候圖片已經放大,那么先將圖片初始化大小和坐標
因為singleTap 和 doubleTap 是屬於同一手勢類,會產生手勢沖突,所以需要
[singleTap requireGestureRecognizerToFail:doubleTap];在執行doubleTap的時候注銷掉singleTap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~然后高潮來了~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~我是可愛的分割線~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最主要的操作是 doubleTap 和pinchGesture,這也是花了我最多時間的兩個問題
首先講一下doubleTap的思想,大家注意觀察微信的圖片瀏覽器,doubleTap在執行的時候會得到一個在View的點 CGPoint tapPoint = [doubletap locationInView:doubletap.view];
然后雙擊后,放大UIImageView,然后通過設定contentoffset偏移量將 tapPoint 移到屏幕最中間,這是雙擊的點包含在圖片里的情況,另外一種情況,是雙擊的點在圖片外,然后點在圖片外又有 左上,右上,左下,右下四種情況。分別將圖片放大然后,圖片左上,右上,左下,右下四個方向貼邊顯示
然后根據tapPoint的x,y判斷四種不同的情況
tapX,tapY是tapPoint的x,y imgY是圖片的y值,imgHeight是圖片的Height
if (tapY<imgY) { //上面 pointType = XJAlbumOutImgViewPointLeftUp; if (tapX>myScreenWidth/2) { pointType = XJAlbumOutImgViewPointRightUp; } isOutImgView = YES; } else if(tapY>imgY+imgHeight) { //下面 pointType = XJAlbumOutImgViewPointLeftDown; if (tapX>myScreenWidth/2) { pointType = XJAlbumOutImgViewPointRightDown; } isOutImgView = YES; }
if (isOutImgView) { //如果點擊的是在圖片外面 NSLog(@"isout"); switch (pointType) { case XJAlbumOutImgViewPointLeftUp: { singleScrollView.contentOffset = CGPointMake(0, 0); } break; case XJAlbumOutImgViewPointLeftDown: { singleScrollView.contentOffset = CGPointMake(0, imgview.frame.size.height - myScreenHeight); } break; case XJAlbumOutImgViewPointRightDown: { singleScrollView.contentOffset = CGPointMake(imgview.frame.size.width - myScreenWidth, imgview.frame.size.height - myScreenHeight); } break; case XJAlbumOutImgViewPointRightUp: { singleScrollView.contentOffset = CGPointMake(imgview.frame.size.width - myScreenWidth, 0); } break; default: break; } } else { //將雙擊的點設置到屏幕的中心 先計算出點距圖片邊緣的距離,然后根據比例求出offsetX; imgX,imgY 分別是圖片的 x,y 坐標值 CGFloat offsetX = (tapX-imgX)*maxScale - myScreenWidth/2; CGFloat offsetY = (tapY-imgY)*maxScale - myScreenHeight/2; //如果超出最大范圍,則設置邊界值 offsetY = offsetY<0?0:offsetY; offsetY = offsetY>imgview.frame.size.height-myScreenHeight?imgview.frame.size.height-myScreenHeight:offsetY; offsetX = offsetX<0?0:offsetX; offsetX = offsetX>imgview.frame.size.width - myScreenWidth?imgview.frame.size.width - myScreenWidth:offsetX; singleScrollView.contentOffset = CGPointMake(offsetX,offsetY); } isBigger = YES;
然后就是捏合手勢,捏合手勢 主要的兩點是 實時的根據放大的比例來改變 UIimageView的size , UIScrollView的contentSize,contentoffset
捏合手勢 pinchGesture的思想是 獲取手勢開始時,兩點的中心點,然后計算出 該中心點在屏幕中的相對位置 , 在手勢變化的時候,保持這個相對位置不改變。
// 變量offsetPinchX 是 scrollview 的 contentoffset.x xInScreen 是 中心點在屏幕的相對位置,因為手勢獲取的點是相對手勢所在View上的相對位置,所以要減去 scrollview 的 x 偏移量
if (pinchGes.state == UIGestureRecognizerStateBegan) {
oldFirstPoint = [pinchGes locationOfTouch:0 inView:pinchGes.view];
oldSecondPoint = [pinchGes locationOfTouch:1 inView:pinchGes.view];
oldLength = [self caculateLengthBetweenP1:oldFirstPoint P2:oldSecondPoint];
//計算出初始中心點
centrePoint = CGPointMake((oldFirstPoint.x+oldSecondPoint.x)/2,(oldSecondPoint.y+oldFirstPoint.y)/2);
xInScreen = centrePoint.x - offsetPinchX;
}
// minSize 是 初始的size newSize 通過計算 兩個點之間的值的比例來獲得
biggerScale = newLength/oldLength;
newSize = CGSizeMake(oldSize.width*biggerScale,oldSize.height*biggerScale);
CGFloat newScale = newSize.width / minSize.width; // 算出 在屏幕的點 if (newSize.width < maxSize.width && newScale>1) { offsetPinchX = xInScreen * (newScale - 1); } if (offsetPinchX<0) { offsetPinchX = 0; } if (offsetPinchX>(newSize.width - myScreenWidth)) { offsetPinchX = newSize.width - myScreenWidth; } NSLog(@"%f ------ %f ------%f",offsetPinchX,centrePoint.x,newScale); if (newSize.width == maxSize.width) { } else { singleScroll.contentOffset = CGPointMake(offsetPinchX, 0); }