需求分析
在App的图片查看中常见有以下功能:
图片随用户手指的点击,会进行相应区域的缩放,虽然这个简单的功能十分常见,实现起来并不难,但常在群里见人问,故略作说明:
视图层次
在此图片显示中 之需要一个UIScrollView和一个UIImageView即可,在一个scrollView 上添加一个imageView,在显示图片的时间,根据图片尺寸调整scrollView的contentSize以便能完全显示并可以移动查看。
- (void)setupUI {
self.view.backgroundColor = [UIColor blackColor];
self.automaticallyAdjustsScrollViewInsets = NO;
_scrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
_scrollView.maximumZoomScale = 2.0;
_scrollView.minimumZoomScale = 1.0;
_scrollView.delegate = self;
[self.view addSubview:_scrollView];
//显示照片的imageView
_imageView = [[UIImageView alloc]init];
_imageView.userInteractionEnabled = YES;
_imageView.center = self.view.center;
//长按保存手势
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[_imageView addGestureRecognizer:longPress];
[_scrollView addSubview:_imageView];
//双击缩放手势
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
doubleTap.numberOfTapsRequired = 2;
[_imageView addGestureRecognizer:doubleTap];
}
图片加载显示:
- (void)loadImage {
[_imageView sd_setImageWithURL:_url placeholderImage:_placeholder options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
//图片下载进度 为后期要求加进度条预留
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
//如果图片下载失败 则直接返回
if (image == nil) {
return ;
}
_imageView.image = image;
//设置imageView的位置
[self setImagePosition:image];
}];
}
图片imageView的位置显示:
- (void)setImagePosition:(UIImage *)image {
CGSize size = [self imageSizeWithScreen:image];
_imageView.frame = CGRectMake(0, 0, size.width, size.height);
_scrollView.contentSize = size;
if (size.height < _scrollView.bounds.size.height) {
CGFloat offsetY = (_scrollView.bounds.size.height - size.height) * 0.5;
_scrollView.contentInset = UIEdgeInsetsMake(offsetY, 0, offsetY, 0);
}}
至此图片的正常显示及位置的显示都已经可正常实现,至于其他一些功能可根据需要自己添加,此处只简单介绍双击缩放功能;
UIScrollView缩放
要让滚动视图可以缩放需要时设置minimumZoomScale
和maximumZoomScale
两个属性的值(默认为1),还需要在滚动视图的代理中实现viewForZoomingInScrollView:
方法
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
该方法返回滚动视图中哪个子视图是可以缩放的,如果滚动视图有多个子视图,但是通常我们需要缩放整个滚动视图的内容,那么将多个视图放在一个视图即可,在将这个视图成为滚动视图的子视图。
滚动视图通过对捏合手势的响应进行缩放,如果缩放超出了我们设置的限制,当手势结束时,尺寸退回到我们设置的限制。如果想要严格的限制缩放不超过我们设置的限制,将bouncesZoom
设置为NO
即可。
至此图片查看的正常显示 及适当的捏合缩放已经实现;
在某种情况下,比如我们需双击要进行缩放的时候,就要用代码进行缩放,使用下面两个方法:
- (void)setZoomScale:(CGFloat)scale animated:(BOOL)animated NS_AVAILABLE_IOS(3_0);
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated NS_AVAILABLE_IOS(3_0);
- setZoomScale:animated: 根据比例缩放
- zoomToRect:animated: 给定矩形的大小进行缩放
在图片查看中常用的是zoomToRect:animated:
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated
,把从scrollView里截取的矩形区域缩放到整个scrollView当前可视的frame里面。如果截取的区域大于scrollView的frame时,图片缩小,
如果截取区域小于frame,会看到图片放大。一般情况下rect需要自己计算出来。即要把用户点击坐标附近的区域内容在scrollViewl里进行缩放
例如:若要把scrollView原来坐标点为(50,60)的点的周围内容在scrollView里放大一倍,可以求出需要从scrollView里截取图片的frame,当然主要是求截取图片坐标原点,内容放大一倍,那么截取图片的大小宽度肯定是
scrollView的frame大小一半。如下列方法:
/** 计算点击点所在区域frame */
- (CGRect)getRectWithScale:(CGFloat)scale andCenter:(CGPoint)center{
CGRect newRect = CGRectZero;
newRect.size.width = _scrollView.frame.size.width/scale;
newRect.size.height = _scrollView.frame.size.height/scale;
newRect.origin.x = center.x - newRect.size.width * 0.5;
newRect.origin.y = center.y - newRect.size.height * 0.5;
return newRect;
}
在双击手势中作如下处理即可:
- (void)doubleTap:(UITapGestureRecognizer *)recognizer {
if (_scrollView.zoomScale > 1.0) {
[_scrollView setZoomScale:1.0 animated:YES];
} else {
CGPoint touchPoint = [recognizer locationInView:_imageView];
CGFloat scale = _scrollView.maximumZoomScale;
CGRect newRect = [self getRectWithScale:scale andCenter:touchPoint];
[_scrollView zoomToRect:newRect animated:YES];
}
}
缩放逻辑视图(画图技术有限,勿喷)