iOS基礎 - 相片瀏覽器

1、需求分析

點擊照片從當前照片位置動畫彈出新的視圖控制器顯示選中的照片,新的視圖控制器爲全屏顯示,背景爲黑色,再次點擊照片動畫縮小至當前選中的照片位置,雙擊放大照片,若是已經放大則縮小,在新的視圖控制器中滑動手指,能夠在照片之間切換,當前顯示的照片支持手指捏合手勢,放大或縮小照片,照片切換時,在照片的下方顯示標籤提示當前顯示的照片數量及照片總數。數組

性能優化:點擊照片從當前照片位置動畫彈出新的視圖控制器顯示選中的照片(非modal、非push瀏覽器

新的視圖控制器爲全屏顯示,背景爲黑色(修改UIApplication的狀態欄),再次點擊照片動畫縮小至當前選中的照片位置(照片視圖須要與父視圖中的UIImageView創建關聯),在新的視圖控制器中滑動手指,能夠在照片之間切換(UIScrollView的分頁支持),當前顯示的照片支持手指捏合手勢,放大或縮小照片(UIScrollView的代理方法支持圖片縮放),照片切換時,在照片的下方顯示標籤提示當前顯示的照片數量及照片總數(開啓新的視圖控制器前,須要傳入照片數組)緩存

2、調整瀑布流

因網絡抓取JSON數據的問題,改成從本地plist文件加載照片數據文件,修改MGJData,增長大圖URL,修改WaterFlowView中的generateCacheData方法,在從新加載數據前刪除全部子視圖,建立PhotoBowser分組,保存照片瀏覽器代碼性能優化

3、創建照片瀏覽器所需文件

PhotoBowserViewController:負責照片瀏覽控制網絡

PhotoView:顯示單張照片,繼承自UIScrollViewapp

PhotoToolbarView:照片工圖欄視圖,顯示保存按鈕和照片索引ide

PhotoModel:照片數據模型類,保存照片瀏覽器的數據性能

4、創建數據模型

+ (id)photoModelWithUrl:(NSURL *)url index:(NSInteger)index;優化

// 圖像Url動畫

@property (strong, nonatomic) NSURL *url;

// 圖像索引

@property (assign, nonatomic) NSInteger index;

5、實例化視圖

// 1. 隱藏狀態欄

UIApplication *app = [UIApplication sharedApplication];

// 記錄初始的狀態欄隱藏狀況

_defaultStatusBarHidden = app.statusBarHidden;

[app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];

 

// 2. 實例化滾動視圖

_scrollView = [[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds];

[_scrollView setBackgroundColor:[UIColor blackColor]];

 

// 暫時添加點按手勢,關閉視圖控制器

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap)];

[_scrollView addGestureRecognizer:tap];

 

// 3. 將滾動視圖設置爲根視圖

self.view = _scrollView;

6、顯示&隱藏

l 顯示

// 爲了與調用視圖器徹底解耦,使用appwindow實現視圖控制器的顯示

UIWindow *window = [UIApplication sharedApplication].keyWindow;

// 將根視圖添加到window中,會疊加在上級窗口上

[window addSubview:self.view];

// 將當前視圖控制器做爲子視圖控制器,添加到window的根視圖控制器中

[window.rootViewController addChildViewController:self];

l 隱藏

[[UIApplication sharedApplication]setStatusBarHidden:_defaultStatusBarHidden];

[self.view removeFromSuperview];

[self removeFromParentViewController];

7、修改WaterFlowView視圖

cellFramesArray屬性移動到.h文件中,以保證照片瀏覽器視圖控制器能夠獲得全部照片的位置

8、調整顯示照片瀏覽器方法

for (MGJData *data in self.dataList) {

    // 獲取單元格視圖的位置

      CGRect frame = [self.waterFlowView.cellFramesArray[index]CGRectValue];

    CGRect srcFrame = [self.waterFlowView convertRect:frame toView:controller.view];

    PhotoModel *p = [PhotoModel photoModelWithUrl:data.largeImage index:index srcFrame:srcFrame];

    [arrayM addObject:p];

    index++;

}

controller.photoList = arrayM;

controller.currentPhotoIndex = indexPath.row;

9、照片視圖

經過setter屬性設置照片

// 佔位圖像

UIImage *image = [[UIImage alloc]init];

// 從網絡加載圖像

__unsafe_unretained PhotoView *photoView = self;

[_imageView setImageWithURL:_photo.url placeholderImage:image options:SDWebImageRetryFailed | SDWebImageProgressiveDownload progress:^(NSUInteger receivedSize, long long expectedSize) {

} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {

    // 記錄圖像

    [photo setImage:image];

    [photoView adjustImageFrame];

}];

10、設置照片顯示尺寸

// 2) 以寬度計算比例

CGFloat minScale = boundW / imageW;

if (minScale > 1.0) {

    minScale = 1.0;

}

CGFloat maxScale = 2.0;

 

// 3) 設置視圖的縮放比例

self.minimumZoomScale = minScale;

self.maximumZoomScale = maxScale;

 

// 若是圖片超出屏幕大小,須要縮放顯示

self.zoomScale = minScale;

 

// 4) 設置內容尺寸

CGRect imageFrame = CGRectMake(0, 0, boundW, imageH * minScale);

self.contentSize = CGSizeMake(imageFrame.size.width, imageFrame.size.height);

 

// 5) 計算圖像位置

if (imageFrame.size.height < boundH) {

    imageFrame.origin.y = (boundH - imageFrame.size.height) / 2.0;

}

11、若是是初次顯示,播放動畫效果

// 6) 若是是初次顯示,顯示動畫效果

if (_photo.isFirstShow) {

    [_imageView setFrame:_photo.srcFrame];

    [UIView animateWithDuration:0.3f animations:^{

        [_imageView setFrame:imageFrame];

    }];

} else {

    [_imageView setFrame:imageFrame];

}

12、照片視圖的縮放處理

#pragma mark - UIScrollView代理方法

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView

{

    return _imageView;

}

十3、照片視圖,增長雙擊手勢

若是照片已經放大則縮小至初始比例

不然根據用戶點擊位置放大圖像

if (self.zoomScale == self.maximumZoomScale) {

    [self setZoomScale:self.minimumZoomScale animated:YES];

} else {

    CGPoint location = [recognizer locationInView:self];

    [self zoomToRect:CGRectMake(location.x, location.y, 1, 1) animated:YES];

}

十4、照片視圖,增長單擊手勢隱藏照片(座標轉換)

#pragma mark 隱藏照片視圖

- (void)hide {

    if (_isDoubleTap) return;

    // 滾動視圖復位

      self.contentOffset = CGPointZero;

    [UIView animateWithDuration:1.0f animations:^{

        [_imageView setFrame:_photo.srcFrame];

        [self.photoViewDelegate photoViewDidSingleTap:self];

    } completion:^(BOOL finished) {

        [self.photoViewDelegate photoViewDidZoomOut:self];

    }];

}

#pragma mark 單擊手勢

- (void)singleTap:(UITapGestureRecognizer *)recognizer {

    _isDoubleTap = NO;

    // 增長時間延時,確保變量數值更改生效

    [self performSelector:@selector(hide) withObject:nil afterDelay:0.2f];

}

十5、提示,隱藏照片時須要兩個代理方法處理

#pragma mark 照片視圖代理方法

- (void)photoViewDidSingleTap:(PhotoView *)photoView

{

    [[UIApplication sharedApplication]setStatusBarHidden:_defaultStatusBarHidden];

    // 設置成透明顏色

    [self.view setBackgroundColor:[UIColor clearColor]];

}

 

- (void)photoViewDidZoomOut:(PhotoView *)photoView

{

    [self.view removeFromSuperview];

    [self removeFromParentViewController];

}

十6、查詢可重用照片視圖

#pragma mark 查詢可重用照片視圖

- (PhotoView *)dequeueReusablePhotoView

{

    // 預設緩存集合已經存在而且工做正常

      PhotoView *photoView = [_reusablePhotoViews anyObject];

 

    // 從緩存集合中刪除照片視圖

      if (photoView) {

        [_reusablePhotoViews removeObject:photoView];

    }

    return photoView;

}

十7、利用photoList setter方法

#pragma mark photoList setter方法,處理視圖緩存

- (void)setPhotoList:(NSArray *)photoList

{

    _photoList = photoList;

    _visiblePhotoViewDict = [NSMutableDictionary dictionary];

    _reusablePhotoViews = [NSMutableSet set];

}

十8、經過可見視圖字典作照片視圖優化

// 在可見視圖字典中查詢是否存在照片視圖

PhotoView *photoView = [_visiblePhotoViewDict objectForKey:@(index)];

if (photoView == nil) {

    photoView = [self dequeueReusablePhotoView];

    if (photoView == nil) {

        photoView = [[PhotoView alloc]init];

        [photoView setPhotoViewDelegate:self];

    }

    PhotoModel *photo = _photoList[index];

    CGFloat w = self.view.bounds.size.width;

    CGFloat h = self.view.bounds.size.height;

    CGRect photoFrame = CGRectMake(index * w, 0, w, h);

    [photoView setFrame:photoFrame];

    [photoView setPhoto:photo];

    [self.view addSubview:photoView];

    // 加入可見視圖字典

    [_visiblePhotoViewDict setObject:photoView forKey:@(index)];

}

十9、在視圖滾動中止時,調整緩存數據

NSInteger index = (NSInteger)_scrollView.contentOffset.x / _scrollView.bounds.size.width;

if (index != _currentPhotoIndex) {

    PhotoView *photoView = _visiblePhotoViewDict[@(_currentPhotoIndex)];

    [_visiblePhotoViewDict removeObjectForKey:@(_currentPhotoIndex)];

    [photoView removeFromSuperview];

    [_reusablePhotoViews addObject:photoView];

    _currentPhotoIndex = index;

相關文章
相關標籤/搜索