點擊照片從當前照片位置動畫彈出新的視圖控制器顯示選中的照片,新的視圖控制器爲全屏顯示,背景爲黑色,再次點擊照片動畫縮小至當前選中的照片位置,雙擊放大照片,若是已經放大則縮小,在新的視圖控制器中滑動手指,能夠在照片之間切換,當前顯示的照片支持手指捏合手勢,放大或縮小照片,照片切換時,在照片的下方顯示標籤提示當前顯示的照片數量及照片總數。數組
性能優化:點擊照片從當前照片位置動畫彈出新的視圖控制器顯示選中的照片(非modal、非push)瀏覽器
新的視圖控制器爲全屏顯示,背景爲黑色(修改UIApplication的狀態欄),再次點擊照片動畫縮小至當前選中的照片位置(照片視圖須要與父視圖中的UIImageView創建關聯),在新的視圖控制器中滑動手指,能夠在照片之間切換(UIScrollView的分頁支持),當前顯示的照片支持手指捏合手勢,放大或縮小照片(UIScrollView的代理方法支持圖片縮放),照片切換時,在照片的下方顯示標籤提示當前顯示的照片數量及照片總數(開啓新的視圖控制器前,須要傳入照片數組)緩存
因網絡抓取JSON數據的問題,改成從本地plist文件加載照片數據文件,修改MGJData,增長大圖URL,修改WaterFlowView中的generateCacheData方法,在從新加載數據前刪除全部子視圖,建立PhotoBowser分組,保存照片瀏覽器代碼。性能優化
PhotoBowserViewController:負責照片瀏覽控制網絡
PhotoView:顯示單張照片,繼承自UIScrollViewapp
PhotoToolbarView:照片工圖欄視圖,顯示保存按鈕和照片索引ide
PhotoModel:照片數據模型類,保存照片瀏覽器的數據性能
+ (id)photoModelWithUrl:(NSURL *)url index:(NSInteger)index;優化
// 圖像Url動畫
@property (strong, nonatomic) NSURL *url;
// 圖像索引
@property (assign, nonatomic) NSInteger index;
// 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;
l 顯示
// 爲了與調用視圖器徹底解耦,使用app的window實現視圖控制器的顯示
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];
將cellFramesArray屬性移動到.h文件中,以保證照片瀏覽器視圖控制器能夠獲得全部照片的位置
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;
經過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];
}];
// 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;
}
// 6) 若是是初次顯示,顯示動畫效果
if (_photo.isFirstShow) {
[_imageView setFrame:_photo.srcFrame];
[UIView animateWithDuration:0.3f animations:^{
[_imageView setFrame:imageFrame];
}];
} else {
[_imageView setFrame:imageFrame];
}
#pragma mark - UIScrollView代理方法
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return _imageView;
}
若是照片已經放大則縮小至初始比例
不然根據用戶點擊位置放大圖像
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];
}
#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];
}
#pragma mark 照片視圖代理方法
- (void)photoViewDidSingleTap:(PhotoView *)photoView
{
[[UIApplication sharedApplication]setStatusBarHidden:_defaultStatusBarHidden];
// 設置成透明顏色
[self.view setBackgroundColor:[UIColor clearColor]];
}
- (void)photoViewDidZoomOut:(PhotoView *)photoView
{
[self.view removeFromSuperview];
[self removeFromParentViewController];
}
#pragma mark 查詢可重用照片視圖
- (PhotoView *)dequeueReusablePhotoView
{
// 預設緩存集合已經存在而且工做正常
PhotoView *photoView = [_reusablePhotoViews anyObject];
// 從緩存集合中刪除照片視圖
if (photoView) {
[_reusablePhotoViews removeObject:photoView];
}
return photoView;
}
#pragma mark photoList setter方法,處理視圖緩存
- (void)setPhotoList:(NSArray *)photoList
{
_photoList = photoList;
_visiblePhotoViewDict = [NSMutableDictionary dictionary];
_reusablePhotoViews = [NSMutableSet set];
}
// 在可見視圖字典中查詢是否存在照片視圖
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)];
}
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;
}