这几天在做项目的时候,碰到了要用图片浏览器的需求,在网上找了一些资料,发现大多的做法不是说很好理解,然后就自己试着用UICollectionView写了简单的图片浏览器,做了简单的过渡动画,也可以实现图片的缩放。
下图是基础的效果:接下来是大致的步骤讲解:
demo1界面的搭建
- 首先我们需要利用创建一个控制器,然后在控制器上面搭建collectionView
- collectionView的创建首先创建UICollectionViewFlowLayout 的对象,设置布局的滚动方式,和每个item的尺寸, 然后创建collecitonView
UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init];
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.itemSize = CGSizeMake(SCREENWIDTH / 4 - 1, SCREENWIDTH / 4 - 1);
_collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
_collectionView.frame = CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT);
_collectionView.contentInset = UIEdgeInsetsMake(45 * W, 0, 57, 0);
[self.view addSubview:_collectionView];
- 接下来设置好代理 并注册cell,来让cell进行循环利用
_collectionView.delegate = self;
_collectionView.dataSource = self;
//注册cell
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"table"];
- 接下来实现数据源的方法,然后在接下来的几个方法
//每组中item的个数
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
//cell的创建和数据的提供
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
//每行之间的最小间距
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
//每个item(cell)的最小间距
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
//选中cell时候要执行的操作
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
//在这个里面我们要完成将indexPath第二个界面的操作
}
我忽略了数据提供的具体操作,自己可以找数据实现上面的数据源方法,然后这时候得到的界面应该如下图所示:
第二个界面的搭建
这时候我们有两种做法可以参考:
- 一种是直接跳转另一个控制器,在控制器中再创建collectionView,进行相应的操作
- 我们直接自定义一个View,在View上面直接创建collectionView,然后直接把这个View在需要的时候利用KeyWindow改到第一个控制器上面,在我们需要的时候再进行移除
我选择的是第二种方法
- 我们直接自定义1个View,设置View和屏幕的宽高相同,然后直接定义collectionView,和上面第一个界面的搭建大同小异,只需要把每个item的大小直接设置为屏幕的大小。滚动的方向设置为水平滚动。
//滚动的方向设置为水平滚动
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.itemSize = CGSizeMake(SCREENWIDTH, SCREENHEIGHT);
- 接下来我们需要自定义cell来完成接下来的操作,拿到第一个页面indexPath,然后根据indexPath.row计算出初始化的时候,我们colletionView的偏移量,来进行定位我们到底选择了哪一张图片,而且我们两组数据其实用的是同一组数据源。
self.collectionView.contentOffset = CGPointMake(SCREENWIDTH * index.row, 0);
到现在我们两个界面的搭建基本完毕,最关键的一点是实现界面的交互,和第二个界面的图片的缩放
缩放问题
- 我们需要在自定义的cell里面放入等同屏幕大小的scrollView,并设置如下的属性:
self.artScrollView = [[UIScrollView alloc] init];
self.artScrollView.frame = CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT);
self.artScrollView.minimumZoomScale = 0.5;
self.artScrollView.maximumZoomScale = 3.0;
self.artScrollView.showsVerticalScrollIndicator = NO;
self.artScrollView.showsHorizontalScrollIndicator = NO;
self.artScrollView.delegate = self;
[self.contentView addSubview:self.artScrollView];
- 然后在模型的set方法中,完成UIimageView的创建和设置
UIImageView *textimage = [[UIImageView alloc] initWithImage:image];
//移除上一个artimage
[self.artimage removeFromSuperview];
self.artimage = [[UIImageView alloc] init];
self.artimage.contentMode = UIViewContentModeScaleAspectFit;
self.artimage.frame = [self setImage:textimage];
self.artimage.image = image;
[self.artScrollView addSubview:self.artimage];
//设置scroll的contentsize的frame
self.artScrollView.contentSize = self.artimage.frame.size;
- 设置scrollView的缩放内容
//这个方法的返回值决定了要缩放的内容(只能是UISCrollView的子控件)
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.artimage;
}
- 而接下来两个方法则是实现图片缩放时候让图片仍然居中,和设置imageView的frame来让图片根据自己的大小,自适应屏幕
//控制缩放是在中心
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)?
(scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)?
(scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
self.artimage.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX,
scrollView.contentSize.height * 0.5 + offsetY);
}
//根据不同的比例设置尺寸
-(CGRect) setImage:(UIImageView *)imageView
{
CGFloat imageX = imageView.frame.size.width;
CGFloat imageY = imageView.frame.size.height;
CGRect imgfram;
CGFloat CGscale;
BOOL flx = (SCREENWIDTH / SCREENHEIGHT) > (imageX / imageY);
if(flx)
{
CGscale = SCREENHEIGHT / imageY;
imageX = imageX * CGscale;
imgfram = CGRectMake((SCREENWIDTH - imageX) / 2, 0, imageX, SCREENHEIGHT);
return imgfram;
}
else
{
CGscale = SCREENWIDTH / imageX;
imageY = imageY * CGscale;
imgfram = CGRectMake(0, (SCREENHEIGHT - imageY) / 2, SCREENWIDTH, imageY);
return imgfram;
}
}
第二个界面的缩放处理完毕,接下来时如何显示在第一个界面上
- 我们利用KeyWindow可以使第二个界面View直接盖在第一个界面的上面,而要做动画操作,大家可以看下我的做法理解下(原理就是利用蒙版先做动画效果,然后让第二个界面直接盖上去,移除的时候先用CGD定时器延时让View透明,然后在这个时间之后直接移除View就可以)
#第一个界面cell被选中的时候调用的代理方法进行如下操作
UIView * backview = [[UIView alloc]initWithFrame:self.view.bounds];
backview.backgroundColor = [UIColor blackColor];
openartModel * model = self.objcArray[indexPath.row];
//计算位置
CGFloat startX = indexPath.row % 4 * ((SCREENWIDTH - 10) /4) + 15;
CGFloat startY = indexPath.row / 4 * ((SCREENWIDTH - 10) /4)+ 84;
CGFloat animatime = 0.7;
UIImageView * imageview = [[UIImageView alloc]initWithFrame:CGRectMake(startX,startY, ((SCREENWIDTH - 10) /4), ((SCREENWIDTH - 10) /4))];
//加载图片
NSString * str = [NSString stringWithFormat:@"http://www.artp.cc/%@",model.ARTWORK_FILE_ORIGINAL];
imageview.image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:str];
imageview.contentMode = UIViewContentModeScaleAspectFit;
[[UIApplication sharedApplication].keyWindow addSubview:backview];
[[UIApplication sharedApplication].keyWindow addSubview:imageview];
//设置动画显示
[UIView animateWithDuration:animatime animations:^{
CGRect frame = CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT);
imageview.frame = frame;
}];
//添加新的view
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(animatime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
DetailArtView * detailView = [[DetailArtView alloc] initWithFrame:CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT) AndIndex:indexPath];
detailView.objcArray = self.objcArray;
[[[[UIApplication sharedApplication].keyWindow subviews] lastObject] removeFromSuperview];
[[[[UIApplication sharedApplication].keyWindow subviews] lastObject] removeFromSuperview];
[[UIApplication sharedApplication].keyWindow addSubview:detailView];
});