MJPhotoView.m 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. //
  2. // MJZoomingScrollView.m
  3. //
  4. // Created by mj on 13-3-4.
  5. // Copyright (c) 2013年 itcast. All rights reserved.
  6. //
  7. #import "MJPhotoView.h"
  8. #import "MJPhoto.h"
  9. #import "MJPhotoLoadingView.h"
  10. #import "UIImageView+WebCache.h"
  11. #import <QuartzCore/QuartzCore.h>
  12. @interface MJPhotoView ()
  13. {
  14. BOOL _doubleTap;
  15. UIImageView *_imageView;
  16. MJPhotoLoadingView *_photoLoadingView;
  17. }
  18. @end
  19. @implementation MJPhotoView
  20. - (id)initWithFrame:(CGRect)frame
  21. {
  22. if ((self = [super initWithFrame:frame])) {
  23. self.clipsToBounds = YES;
  24. // 图片
  25. _imageView = [[UIImageView alloc] init];
  26. _imageView.contentMode = UIViewContentModeScaleAspectFit;
  27. [self addSubview:_imageView];
  28. // 进度条
  29. _photoLoadingView = [[MJPhotoLoadingView alloc] init];
  30. // 属性
  31. self.backgroundColor = [UIColor clearColor];
  32. self.delegate = self;
  33. self.showsHorizontalScrollIndicator = NO;
  34. self.showsVerticalScrollIndicator = NO;
  35. self.decelerationRate = UIScrollViewDecelerationRateFast;
  36. self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  37. // 监听点击
  38. UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
  39. singleTap.delaysTouchesBegan = YES;
  40. singleTap.numberOfTapsRequired = 1;
  41. [self addGestureRecognizer:singleTap];
  42. UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
  43. doubleTap.numberOfTapsRequired = 2;
  44. [self addGestureRecognizer:doubleTap];
  45. }
  46. return self;
  47. }
  48. #pragma mark - photoSetter
  49. - (void)setPhoto:(MJPhoto *)photo {
  50. _photo = photo;
  51. [self showImage];
  52. }
  53. #pragma mark 显示图片
  54. - (void)showImage
  55. {
  56. if (_photo.firstShow) { // 首次显示
  57. _imageView.image = _photo.placeholder; // 占位图片
  58. _photo.srcImageView.image = nil;
  59. // 不是gif,就马上开始下载
  60. if (![_photo.url.absoluteString hasSuffix:@"gif"]) {
  61. __unsafe_unretained MJPhotoView *photoView = self;
  62. __unsafe_unretained MJPhoto *photo = _photo;
  63. [_imageView sd_setImageWithURL:_photo.url placeholderImage:_photo.placeholder options:SDWebImageRetryFailed|SDWebImageLowPriority completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
  64. photo.image = image;
  65. // 调整frame参数
  66. [photoView adjustFrame];
  67. }];
  68. }
  69. } else {
  70. [self photoStartLoad];
  71. }
  72. // 调整frame参数
  73. [self adjustFrame];
  74. }
  75. #pragma mark 开始加载图片
  76. - (void)photoStartLoad
  77. {
  78. if (_photo.image) {
  79. self.scrollEnabled = YES;
  80. _imageView.image = _photo.image;
  81. } else {
  82. self.scrollEnabled = NO;
  83. // 直接显示进度条
  84. [_photoLoadingView showLoading];
  85. [self addSubview:_photoLoadingView];
  86. __unsafe_unretained MJPhotoView *photoView = self;
  87. __unsafe_unretained MJPhotoLoadingView *loading = _photoLoadingView;
  88. [_imageView sd_setImageWithURL:_photo.url placeholderImage:_photo.srcImageView.image options:SDWebImageRetryFailed|SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
  89. if (receivedSize > kMinProgress)
  90. {
  91. loading.progress = (float)receivedSize/expectedSize;
  92. }
  93. } completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
  94. [photoView photoDidFinishLoadWithImage:image];
  95. }];
  96. }
  97. }
  98. #pragma mark 加载完毕
  99. - (void)photoDidFinishLoadWithImage:(UIImage *)image
  100. {
  101. if (image) {
  102. self.scrollEnabled = YES;
  103. _photo.image = image;
  104. [_photoLoadingView removeFromSuperview];
  105. if ([self.photoViewDelegate respondsToSelector:@selector(photoViewImageFinishLoad:)]) {
  106. [self.photoViewDelegate photoViewImageFinishLoad:self];
  107. }
  108. } else {
  109. [self addSubview:_photoLoadingView];
  110. [_photoLoadingView showFailure];
  111. }
  112. // 设置缩放比例
  113. [self adjustFrame];
  114. }
  115. #pragma mark 调整frame
  116. - (void)adjustFrame
  117. {
  118. if (_imageView.image == nil) return;
  119. // 基本尺寸参数
  120. CGSize boundsSize = self.bounds.size;
  121. CGFloat boundsWidth = boundsSize.width;
  122. CGFloat boundsHeight = boundsSize.height;
  123. CGSize imageSize = _imageView.image.size;
  124. CGFloat imageWidth = imageSize.width;
  125. CGFloat imageHeight = imageSize.height;
  126. // 设置伸缩比例
  127. CGFloat minScale = boundsWidth / imageWidth;
  128. if (minScale > 1) {
  129. minScale = 1.0;
  130. }
  131. CGFloat maxScale = 2.0;
  132. if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
  133. maxScale = maxScale / [[UIScreen mainScreen] scale];
  134. }
  135. self.maximumZoomScale = maxScale;
  136. self.minimumZoomScale = minScale;
  137. self.zoomScale = minScale;
  138. CGRect imageFrame = CGRectMake(0, 0, boundsWidth, imageHeight * boundsWidth / imageWidth);
  139. // 内容尺寸
  140. self.contentSize = CGSizeMake(0, imageFrame.size.height);
  141. // y值
  142. if (imageFrame.size.height < boundsHeight) {
  143. imageFrame.origin.y = floorf((boundsHeight - imageFrame.size.height) / 2.0);
  144. } else {
  145. imageFrame.origin.y = 0;
  146. }
  147. if (_photo.firstShow) { // 第一次显示的图片
  148. _photo.firstShow = NO; // 已经显示过了
  149. _imageView.frame = [_photo.srcImageView convertRect:_photo.srcImageView.bounds toView:nil];
  150. [UIView animateWithDuration:0.3 animations:^{
  151. _imageView.frame = imageFrame;
  152. } completion:^(BOOL finished) {
  153. // 设置底部的小图片
  154. _photo.srcImageView.image = _photo.placeholder;
  155. [self photoStartLoad];
  156. }];
  157. } else {
  158. _imageView.frame = imageFrame;
  159. }
  160. }
  161. #pragma mark - UIScrollViewDelegate
  162. - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  163. return _imageView;
  164. }
  165. #pragma mark - 手势处理
  166. - (void)handleSingleTap:(UITapGestureRecognizer *)tap {
  167. _doubleTap = NO;
  168. [self performSelector:@selector(hide) withObject:nil afterDelay:0.2];
  169. }
  170. - (void)hide
  171. {
  172. if (_doubleTap) return;
  173. // 移除进度条
  174. [_photoLoadingView removeFromSuperview];
  175. self.contentOffset = CGPointZero;
  176. // 清空底部的小图
  177. _photo.srcImageView.image = nil;
  178. CGFloat duration = 0.15;
  179. if (_photo.srcImageView.clipsToBounds) {
  180. [self performSelector:@selector(reset) withObject:nil afterDelay:duration];
  181. }
  182. [UIView animateWithDuration:duration + 0.1 animations:^{
  183. _imageView.frame = [_photo.srcImageView convertRect:_photo.srcImageView.bounds toView:nil];
  184. // gif图片仅显示第0张
  185. if (_imageView.image.images) {
  186. _imageView.image = _imageView.image.images[0];
  187. }
  188. // 通知代理
  189. if ([self.photoViewDelegate respondsToSelector:@selector(photoViewSingleTap:)]) {
  190. [self.photoViewDelegate photoViewSingleTap:self];
  191. }
  192. } completion:^(BOOL finished) {
  193. // 设置底部的小图片
  194. _photo.srcImageView.image = _photo.placeholder;
  195. // 通知代理
  196. if ([self.photoViewDelegate respondsToSelector:@selector(photoViewDidEndZoom:)]) {
  197. [self.photoViewDelegate photoViewDidEndZoom:self];
  198. }
  199. }];
  200. }
  201. - (void)scrollViewDidZoom:(UIScrollView *)scrollView
  202. {
  203. CGRect imageViewFrame = _imageView.frame;
  204. CGRect screenBounds = [UIScreen mainScreen].bounds;
  205. if (imageViewFrame.size.height > screenBounds.size.height)
  206. { imageViewFrame.origin.y = 0.0f;
  207. } else {
  208. imageViewFrame.origin.y = (screenBounds.size.height - imageViewFrame.size.height) / 2.0;
  209. }
  210. _imageView.frame = imageViewFrame;
  211. }
  212. - (void)reset
  213. {
  214. _imageView.image = _photo.capture;
  215. _imageView.contentMode = UIViewContentModeScaleToFill;
  216. }
  217. - (void)handleDoubleTap:(UITapGestureRecognizer *)tap {
  218. _doubleTap = YES;
  219. CGPoint touchPoint = [tap locationInView:self];
  220. if (self.zoomScale == self.maximumZoomScale) {
  221. [self setZoomScale:self.minimumZoomScale animated:YES];
  222. } else {
  223. [self zoomToRect:CGRectMake(touchPoint.x, touchPoint.y, 1, 1) animated:YES];
  224. }
  225. }
  226. - (void)dealloc
  227. {
  228. // 取消请求
  229. [_imageView sd_setImageWithURL:[NSURL URLWithString:@"file:///abc"]];
  230. }
  231. @end