2014年3月8日

Picture Viewer - ios版 以雙層 scrollView 實現


照片瀏覽是很常見的功能,但如何實現與系統相仿的照片瀏覽功能呢?這裡就介紹一下如何在 ios 中實現系統照片瀏覽功能 ( 包含照片換頁,照片縮放功能 )
ios 做圖片縮放與 android 不同的地方在於,ios 是對 scrollView 做縮放即可,android 則需縮放 imageView

外層 scrollView

  1. init 設定 ( View 定義在 MainView.xib 中,這裡只設置部分屬性 )

scrView.contentSize = CGSizeMake(1700, 480);  //設定顯示內容大小
scrView.showsHorizontalScrollIndicator = NO;  //scroll 時不顯示橫向 scroll bar

2. 實作 Delegate 判斷目前頁數

//scroll結束後調用
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
 CGFloat pageWidth = scrollView.frame.size.width;
 NSInteger page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
 
 if (lastPage != page) 
 {
  MyScrollView *aView = (MyScrollView *)[scrView viewWithTag:100+lastPage];
  aView.zoomScale = 1.0;
  
  lastPage = page;
 }
}

3. 加入內層 scrollView

for (int i=0; i<5; i++)
{
 MyScrollView *ascrView = [[MyScrollView alloc] initWithFrame:CGRectMake(340*i, 0, 320, 480)];
 NSString *imgPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%d", i+1] ofType:@"jpg"];
        
 [ascrView showProgressView];
        ascrView.tag = 100+i;
        
 [subviewArray addObject:ascrView];
 [pathArray addObject:imgPath];
        
 //設定 timmer,用來顯示 ProgressView
 theTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(countTotalFrames:) userInfo:nil repeats:YES];

 [scrView addSubview:ascrView];
}

4. 設定 timmer 執行的 method

-(void)countTotalFrames:(NSTimer*)sender{
    NSObject *obj = sender.userInfo;
    
    MyScrollView *ascrView = [subviewArray objectAtIndex:lastPage];
    NSString *imgPath = [pathArray objectAtIndex:lastPage];
    
    //模擬 loading 畫面
    if(ascrView.progressView.progress < 1){
        ascrView.progressView.progress += 0.1;  //設定 progressView 進度,進度範圍為 0~1
    }else{
        [ascrView closeProgressView];
//        [theTimer invalidate];  //關閉 timmer
        ascrView.image = [UIImage imageWithContentsOfFile:imgPath];
    }
}

內層 scrollView

  1. init scrollView、imageView 與 progressView

self.delegate = self;
self.minimumZoomScale = 0.1;  //最小縮小比例
self.maximumZoomScale = 2;  //最大放大比例
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;

imageView  = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[self addSubview:imageView];

//init progressView
CGFloat widthSpace_iPhone = 20;
CGFloat widthSpace_iPad = 50;
CGFloat widthSpace;

isPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;  //判斷是否為 pad

if(isPad){
    widthSpace = widthSpace_iPad;
}else{
    widthSpace = widthSpace_iPhone;
}

self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(10, (self.frame.size.height-10)/2, self.frame.size.width-widthSpace, 30)];
self.progressView.progressViewStyle = UIProgressViewStyleDefault;
self.progressView.progress = 0;  //初始化進度

//將progressView縮放改變其高度
if(isPad){
    CGAffineTransform transform = CGAffineTransformMakeScale(1.0f, 5.0f);
    self.progressView.transform = transform;
}

2. 複寫 setImage method

- (void)setImage:(UIImage *)img
{
 imageView.image = img;
    
    //將原圖縮小符合螢幕大小
    imageView.frame = CGRectMake(0, 10, img.size.width, img.size.height);
    
    //設定原圖比例為最小縮小比例,即最小不能小於原圖
    self.zoomScale = [self getZoomScale];
    self.minimumZoomScale = self.zoomScale;
}

3. 設定 touch 縮放事件 ( 這裡是做 scrollView 的縮放來實現圖片縮放 )

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
 UITouch *touch = [touches anyObject];
 
 if ([touch tapCount] == 2) //兩指click時觸發
 {
  CGFloat zs = self.zoomScale;
  zs = (zs == 1.0) ? self.maximumZoomScale : self.minimumZoomScale;
  
  [UIView beginAnimations:nil context:NULL];  //設置動畫
  [UIView setAnimationDuration:0.3];  //動畫總時間
  self.zoomScale = zs;  //設定滾動條默認的尺度
  [UIView commitAnimations];  //結束動畫
 }
}

※ minimumZoomScale 為滾動條最小尺度;maximumZoomScale 為滾動條最大尺度
4. 設定 scrollView 縮放完成後,重設滾動條的最大與最小值 ( 可縮放的最大為小值 )

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
 //縮放完觸發
 CGFloat zs = scrollView.zoomScale;
 zs = MAX(zs, self.minimumZoomScale);
 zs = MIN(zs, self.maximumZoomScale);
 
 [UIView beginAnimations:nil context:NULL];
 [UIView setAnimationDuration:0.3];
 scrollView.zoomScale = zs;
 [UIView commitAnimations];
}

接著就可以來測試一下摟! ( 以上只擷取部分代碼說明,如果有遇到問題的可以下載範例測試查看 )

References