MJPhotoView.m 8.6 KB

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