MJPhotoView.m 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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 = [UIImage imageNamed:@"deafultjiu"];
  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 completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable 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_setImageWithPreviousCachedImageWithURL:_photo.url placeholderImage:_photo.srcImageView.image options:SDWebImageRetryFailed|SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
  89. if (receivedSize > kMinProgress) {
  90. loading.progress = (float)receivedSize/expectedSize;
  91. }
  92. } completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
  93. [photoView photoDidFinishLoadWithImage:image];
  94. }];
  95. }
  96. }
  97. #pragma mark 加载完毕
  98. - (void)photoDidFinishLoadWithImage:(UIImage *)image
  99. {
  100. if (image) {
  101. self.scrollEnabled = YES;
  102. _photo.image = image;
  103. [_photoLoadingView removeFromSuperview];
  104. if ([self.photoViewDelegate respondsToSelector:@selector(photoViewImageFinishLoad:)]) {
  105. [self.photoViewDelegate photoViewImageFinishLoad:self];
  106. }
  107. } else {
  108. [self addSubview:_photoLoadingView];
  109. [_photoLoadingView showFailure];
  110. }
  111. // 设置缩放比例
  112. [self adjustFrame];
  113. }
  114. #pragma mark 调整frame
  115. - (void)adjustFrame
  116. {
  117. if (_imageView.image == nil) return;
  118. // 基本尺寸参数
  119. CGSize boundsSize = self.bounds.size;
  120. CGFloat boundsWidth = boundsSize.width;
  121. CGFloat boundsHeight = boundsSize.height;
  122. CGSize imageSize = _imageView.image.size;
  123. CGFloat imageWidth = imageSize.width;
  124. CGFloat imageHeight = imageSize.height;
  125. // 设置伸缩比例
  126. CGFloat minScale = boundsWidth / imageWidth;
  127. if (minScale > 1) {
  128. minScale = 1.0;
  129. }
  130. CGFloat maxScale = 2.0;
  131. if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
  132. maxScale = maxScale / [[UIScreen mainScreen] scale];
  133. }
  134. self.maximumZoomScale = maxScale;
  135. self.minimumZoomScale = minScale;
  136. self.zoomScale = minScale;
  137. CGRect imageFrame = CGRectMake(0, 0, boundsWidth, imageHeight * boundsWidth / imageWidth);
  138. // 内容尺寸
  139. self.contentSize = CGSizeMake(0, imageFrame.size.height);
  140. // y值
  141. if (imageFrame.size.height < boundsHeight) {
  142. imageFrame.origin.y = floorf((boundsHeight - imageFrame.size.height) / 2.0);
  143. } else {
  144. imageFrame.origin.y = 0;
  145. }
  146. if (_photo.firstShow) { // 第一次显示的图片
  147. _photo.firstShow = NO; // 已经显示过了
  148. _imageView.frame = [_photo.srcImageView convertRect:_photo.srcImageView.bounds toView:nil];
  149. [UIView animateWithDuration:0.3 animations:^{
  150. self->_imageView.frame = imageFrame;
  151. } completion:^(BOOL finished) {
  152. // 设置底部的小图片
  153. self->_photo.srcImageView.image = self->_photo.placeholder;
  154. [self photoStartLoad];
  155. }];
  156. } else {
  157. _imageView.frame = imageFrame;
  158. }
  159. }
  160. #pragma mark - UIScrollViewDelegate
  161. - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  162. return _imageView;
  163. }
  164. #pragma mark - 手势处理
  165. - (void)handleSingleTap:(UITapGestureRecognizer *)tap {
  166. _doubleTap = NO;
  167. [self performSelector:@selector(hide) withObject:nil afterDelay:0.2];
  168. }
  169. - (void)hide
  170. {
  171. if (_doubleTap) return;
  172. // 移除进度条
  173. [_photoLoadingView removeFromSuperview];
  174. self.contentOffset = CGPointZero;
  175. // 清空底部的小图
  176. _photo.srcImageView.image = nil;
  177. CGFloat duration = 0.15;
  178. if (_photo.srcImageView.clipsToBounds) {
  179. [self performSelector:@selector(reset) withObject:nil afterDelay:duration];
  180. }
  181. [UIView animateWithDuration:duration + 0.1 animations:^{
  182. self->_imageView.frame = [self->_photo.srcImageView convertRect:self->_photo.srcImageView.bounds toView:nil];
  183. // gif图片仅显示第0张
  184. if (self->_imageView.image.images) {self->
  185. _imageView.image = self->_imageView.image.images[0];
  186. }
  187. // 通知代理
  188. if ([self.photoViewDelegate respondsToSelector:@selector(photoViewSingleTap:)]) {
  189. [self.photoViewDelegate photoViewSingleTap:self];
  190. }
  191. } completion:^(BOOL finished) {
  192. // 设置底部的小图片
  193. self->_photo.srcImageView.image = self->_photo.placeholder;
  194. // 通知代理
  195. if ([self.photoViewDelegate respondsToSelector:@selector(photoViewDidEndZoom:)]) {
  196. [self.photoViewDelegate photoViewDidEndZoom:self];
  197. }
  198. }];
  199. }
  200. - (void)reset
  201. {
  202. _imageView.image = _photo.capture;
  203. _imageView.contentMode = UIViewContentModeScaleToFill;
  204. }
  205. - (void)handleDoubleTap:(UITapGestureRecognizer *)tap {
  206. _doubleTap = YES;
  207. CGPoint touchPoint = [tap locationInView:self];
  208. if (self.zoomScale == self.maximumZoomScale) {
  209. [self setZoomScale:self.minimumZoomScale animated:YES];
  210. } else {
  211. [self zoomToRect:CGRectMake(touchPoint.x, touchPoint.y, 1, 1) animated:YES];
  212. }
  213. }
  214. - (void)dealloc
  215. {
  216. // 取消请求
  217. [_imageView sd_setImageWithURL:[NSURL URLWithString:@"file:///abc"]];
  218. }
  219. @end