iOS许多APP中都使用到了图片放大浏览的功能,如淘宝、微信等。最近也琢磨了一些方法,基本可以实现点击图片放大,并且可以左右滑动浏览上一张下一张图片,也可以通过手势撑开放大缩小,可以加上长按保存到相册的功能。具体的做法是子类化UIImageView,添加点击手势,监听手势创建UIScrollView浏览视图,实现左右滑动,每张图片用独自的UIScrollView盛放便可以实现放大缩小旋转等功能。
一、效果
浏览效果和放大效果
二、实现流程
1、子类化UIImageView,取名为ZoomImageView
#import <UIKit/UIKit.h>
@class ZoomImageView;
@protocol ZoomImageViewDelegate <NSObject>
@optional
//图片将要放大
- (void)imageWillZoomIn:(ZoomImageView *)imageView;
//图片已经放大
- (void)imageDidZoomIn:(ZoomImageView *)imageView;
//图片将要隐藏
- (void)imageWillZoomOut:(ZoomImageView *)imageView;
//图片已经隐藏
- (void)imageDidZoomOut:(ZoomImageView *)imageView;
@end
@interface ZoomImageView : UIImageView {
UIImageView *_fullImageView;
}
@property (nonatomic, weak)id<ZoomImageViewDelegate> delegate;
//绑定数据用于浏览
@property (nonatomic,strong)NSMutableArray *imageArray;
//描述
@property (nonatomic,strong)NSMutableArray *desArray;
//当前图片
@property (nonatomic,strong)NSString *nowImage;
- (instancetype)initWithFrame:(CGRect)frame withImage:(NSString *)imageStr;
2、给ZoomImageView添加点击事件,实现放大动画
//是否处于点击状态
_isTap = NO;
//添加点击手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(zoomAction)];
[self addGestureRecognizer:tap];
self.userInteractionEnabled = YES;
//等比例放大缩小
self.contentMode = UIViewContentModeScaleAspectFit;
实现ZoomAction图片放大方法,当zoomImageView 被点击,用[self _createViews]创建放大所需的视图。然后显示_maskView,_maskView的背景设置为黑色,这样原来的图片就将被黑色覆盖,接着获取被点击的图片的frame,将_fullImageView的的坐标设置为被点击图片的坐标,用_fullImageView实现放大动画,放大完成后_fullImageView再次隐藏并移除,这样就实现了放大功能。最后显示用于图片滑动浏览的_photoListView视图。
- (void)zoomAction{
if (_isTap == YES) {
return;
}else{
_isTap = YES;
}
NSLog(@"开始放大");
//调用代理对象将要放大的协议方法
if ([self.delegate respondsToSelector:@selector(imageWillZoomIn:)]) {
[self.delegate imageWillZoomIn:self];
}
[self _createView];
//坐标系由当前视图转化为window的坐标
CGRect frame = [self convertRect:self.bounds toView:self.window];
_fullImageView.frame = frame;
_maskView.alpha = 1;
_maskView.hidden = NO;
//设置动画效果实现放大
[UIView animateWithDuration:0.3 animations:^{
//放大到整个屏幕
_fullImageView.frame = [UIScreen mainScreen].bounds;
} completion:^(BOOL finished) {
_photoListView.hidden = NO;
_maskView.hidden = NO;
_fullImageView.hidden = YES;
//调用代理对象已经放大的协议方法
if ([self.delegate respondsToSelector:@selector(imageDidZoomIn:)]) {
[self.delegate imageDidZoomIn:self];
}
}];
}
当图片被点击的时候,创建放大所需的视图,_maskView为黑色背景视图,_photoListView继承UIView,用于放置浏览图片的视图,_fullImageView继承自UIImageView,用于实现图片放大动画。
//创建大图显示时需要的子视图
- (void)_createView {
if (_photoListView == nil) {
//蒙砂视图
_maskView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
_maskView.backgroundColor = [UIColor blackColor];
_maskView.alpha = 1;
_maskView.hidden = YES;
[self.window addSubview:_maskView];
//图片浏览视图
_photoListView = [[PhotoListView alloc] initWithFrame:[UIScreen mainScreen].bounds];
_photoListView.hidden = YES;
_photoListView.desArray = _desArray;
_photoListView.images = _imageArray;
//计算当前视图为第几张
for(NSInteger i = 0; i < _imageArray.count;i++){
NSString *urlNow = _imageArray[i];
if([_nowImage isEqualToString:urlNow] ){
_photoListView.indexPath = i;
}
}
[self.window addSubview:_photoListView];
//创建大图显示视图
_fullImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_fullImageView.image = self.image;
_fullImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.window addSubview:_fullImageView];
}
}
3、PhotoListView的创建,实现滑动图片浏览
在PhotoListView上创建UIcollectionView,每个cell的大小设置为屏幕大小,每个cell盛放一张图片,滑动方向设置为左右滑动
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(kScreenWidth, kScreenHeight);
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 30;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_collectionView =[[PhotoCollectionView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth + 30,kScreenHeight) collectionViewLayout:layout];
_collectionView.backgroundColor = [UIColor clearColor];
[self addSubview:_collectionView];
此处需要在视图底部创建每张图片的页码和文字提示
//文字显示
_desBg = [[UIView alloc] initWithFrame:CGRectMake(0, kScreenHeight - 85, kScreenWidth, 35)];
_desBg.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4];
[self addSubview:_desBg];
_desLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, kScreenWidth - 20, 35)];
_desLabel.backgroundColor = [UIColor clearColor];
_desLabel.textColor = [UIColor whiteColor];
_desLabel.font = [UIFont systemFontOfSize:13];
_desLabel.textAlignment = NSTextAlignmentLeft;
_desLabel.numberOfLines = 2;
_desLabel.userInteractionEnabled = NO;
[_desBg addSubview:_desLabel];
//创建页码显示
_pageCountLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, kScreenHeight - 50, kScreenWidth, 50)];
_pageCountLabel.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4];
_pageCountLabel.textColor = [UIColor whiteColor];
_pageCountLabel.font = [UIFont systemFontOfSize:15];
_pageCountLabel.textAlignment = NSTextAlignmentCenter;
_pageCountLabel.userInteractionEnabled = NO;
[self addSubview:_pageCountLabel];
滑动时每张图片的页码变化此处我用通知来实现
//接受通知方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(PageChangeAction:) name:@"PageChangeAction" object:nil];
- (void)PageChangeAction:(NSNotification *)text {
NSString *str = text.userInfo[@"nowPage"];
_pageCountLabel.text = [NSString stringWithFormat:@"%li/%lu",[str integerValue] + 1,(unsigned long)_images.count];
if (_descriptionArr.count > 0) {
NSString *desStr = _descriptionArr[[str integerValue]];
if ((NSNull *)desStr != [NSNull null] && desStr != nil) {
_desLabel.text = desStr;
_desBg.hidden = NO;
}else{
_desBg.hidden = YES;
}
}else{
_desBg.hidden = YES;
}
}
4、子类化UICollectionViewCell,在cell上添加滑动视图UIScollView,用UIScollview盛放图片,用于实现图片的拉伸放大,旋转,保存等功能。
在UICollecionViewCell中添加 PhotoScollView,PhotoScollView继承自UIScolloview,用于放置图片。
//子类化滑动视图
scrollView = [[PhotoScrollView alloc] initWithFrame:self.bounds];
[self.contentView addSubview:scrollView];
5、PhotoScollView的实现
此处我只添加了单击手势和双击手势,单击是发送通知隐藏滑动视图,双击是放大图片或者缩小图片。因为同时涉及单击和双击,所以要处理单击和双击的冲突。这里的处理方法是双击手势触发时,让单击手势暂时失效 [singleTap requireGestureRecognizerToFail:doubleTap];
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
//子视图
imageView = [[UIImageView alloc] initWithFrame:self.bounds];
//等比例放大
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:imageView];
//指定代理
self.delegate = self;
//缩放倍数
self.maximumZoomScale = 3;
self.minimumZoomScale = .5;
//双击手势
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapAction:)];
//设置手指的数量
doubleTap.numberOfTouchesRequired = 1;
//点击的数量
doubleTap.numberOfTapsRequired = 2;
//将手势添加到滑动视图上
[self addGestureRecognizer:doubleTap];
//单击手势
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction)];
[self addGestureRecognizer:singleTap];
//双击手势触发时,让单击手势暂时失效
[singleTap requireGestureRecognizerToFail:doubleTap];
}
return self;
}
- (void)setImageUrl:(NSString *)imageUrl{
//填充数据
//[imageView sd_setImageWithURL:[NSURL URLWithString:imageUrl]];
imageView.image = [UIImage imageNamed:imageUrl];
}
#pragma mark UITapGestureRecognizer
//单击手势
- (void)singleTapAction{
//发送通知结束浏览
[[NSNotificationCenter defaultCenter] postNotificationName:@"HideShowViewNotification" object:nil];
}
//双击调用的方法
- (void)doubleTapAction:(UITapGestureRecognizer *)tap{
if (self.zoomScale != 1) { //不是正常倍数
// self.zoomScale = 1; //还原
[self setZoomScale:1 animated:YES];
}else{
// self.zoomScale = 3;
[self setZoomScale:3 animated:YES];
}
}
#pragma mark UIScrollViewDelegate
//返回放大的视图
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return imageView;
}
6、
有待完善的地方
放大后的图片和放大前的图片不应该是同一张,放大前应该用缩略图,节约流量,提高显示速度,放大后应该用大图,展示清晰图片。并且真实项目中应该考虑图片缓存等问题。
三、demo链接
CSDN:http://download.csdn.net/detail/fivenineminutes/9715654
github:https://github.com/59minutes/JLImageList