TZPhotoPreviewCell.m 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. //
  2. // TZPhotoPreviewCell.m
  3. // TZImagePickerController
  4. //
  5. // Created by 谭真 on 15/12/24.
  6. // Copyright © 2015年 谭真. All rights reserved.
  7. //
  8. #import "TZPhotoPreviewCell.h"
  9. #import "TZAssetModel.h"
  10. #import "UIView+Layout.h"
  11. #import "TZImageManager.h"
  12. #import "TZProgressView.h"
  13. #import "TZImageCropManager.h"
  14. @interface TZPhotoPreviewCell ()
  15. @end
  16. @implementation TZPhotoPreviewCell
  17. - (instancetype)initWithFrame:(CGRect)frame {
  18. self = [super initWithFrame:frame];
  19. if (self) {
  20. self.backgroundColor = [UIColor blackColor];
  21. self.previewView = [[TZPhotoPreviewView alloc] initWithFrame:self.bounds];
  22. __weak typeof(self) weakSelf = self;
  23. [self.previewView setSingleTapGestureBlock:^{
  24. if (weakSelf.singleTapGestureBlock) {
  25. weakSelf.singleTapGestureBlock();
  26. }
  27. }];
  28. [self.previewView setImageProgressUpdateBlock:^(double progress) {
  29. if (weakSelf.imageProgressUpdateBlock) {
  30. weakSelf.imageProgressUpdateBlock(progress);
  31. }
  32. }];
  33. [self addSubview:self.previewView];
  34. }
  35. return self;
  36. }
  37. - (void)setModel:(TZAssetModel *)model {
  38. _model = model;
  39. _previewView.asset = model.asset;
  40. }
  41. - (void)recoverSubviews {
  42. [_previewView recoverSubviews];
  43. }
  44. - (void)setAllowCrop:(BOOL)allowCrop {
  45. _allowCrop = allowCrop;
  46. _previewView.allowCrop = allowCrop;
  47. }
  48. - (void)setCropRect:(CGRect)cropRect {
  49. _cropRect = cropRect;
  50. _previewView.cropRect = cropRect;
  51. }
  52. @end
  53. @interface TZPhotoPreviewView ()<UIScrollViewDelegate>
  54. @end
  55. @implementation TZPhotoPreviewView
  56. - (instancetype)initWithFrame:(CGRect)frame {
  57. self = [super initWithFrame:frame];
  58. if (self) {
  59. _scrollView = [[UIScrollView alloc] init];
  60. _scrollView.frame = CGRectMake(10, 0, self.tz_width - 20, self.tz_height);
  61. _scrollView.bouncesZoom = YES;
  62. _scrollView.maximumZoomScale = 2.5;
  63. _scrollView.minimumZoomScale = 1.0;
  64. _scrollView.multipleTouchEnabled = YES;
  65. _scrollView.delegate = self;
  66. _scrollView.scrollsToTop = NO;
  67. _scrollView.showsHorizontalScrollIndicator = NO;
  68. _scrollView.showsVerticalScrollIndicator = NO;
  69. _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  70. _scrollView.delaysContentTouches = NO;
  71. _scrollView.canCancelContentTouches = YES;
  72. _scrollView.alwaysBounceVertical = NO;
  73. [self addSubview:_scrollView];
  74. _imageContainerView = [[UIView alloc] init];
  75. _imageContainerView.clipsToBounds = YES;
  76. _imageContainerView.contentMode = UIViewContentModeScaleAspectFill;
  77. [_scrollView addSubview:_imageContainerView];
  78. _imageView = [[UIImageView alloc] init];
  79. _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
  80. _imageView.contentMode = UIViewContentModeScaleAspectFill;
  81. _imageView.clipsToBounds = YES;
  82. [_imageContainerView addSubview:_imageView];
  83. UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
  84. [self addGestureRecognizer:tap1];
  85. UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
  86. tap2.numberOfTapsRequired = 2;
  87. [tap1 requireGestureRecognizerToFail:tap2];
  88. [self addGestureRecognizer:tap2];
  89. [self configProgressView];
  90. }
  91. return self;
  92. }
  93. - (void)configProgressView {
  94. _progressView = [[TZProgressView alloc] init];
  95. static CGFloat progressWH = 40;
  96. CGFloat progressX = (self.tz_width - progressWH) / 2;
  97. CGFloat progressY = (self.tz_height - progressWH) / 2;
  98. _progressView.frame = CGRectMake(progressX, progressY, progressWH, progressWH);
  99. _progressView.hidden = YES;
  100. [self addSubview:_progressView];
  101. }
  102. - (void)setModel:(TZAssetModel *)model {
  103. _model = model;
  104. [_scrollView setZoomScale:1.0 animated:NO];
  105. if (model.type == TZAssetModelMediaTypePhotoGif) {
  106. [[TZImageManager manager] getOriginalPhotoDataWithAsset:model.asset completion:^(NSData *data, NSDictionary *info, BOOL isDegraded) {
  107. if (!isDegraded) {
  108. self.imageView.image = [UIImage sd_tz_animatedGIFWithData:data];
  109. [self resizeSubviews];
  110. }
  111. }];
  112. } else {
  113. self.asset = model.asset;
  114. }
  115. }
  116. - (void)setAsset:(id)asset {
  117. _asset = asset;
  118. [[TZImageManager manager] getPhotoWithAsset:asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  119. self.imageView.image = photo;
  120. [self resizeSubviews];
  121. _progressView.hidden = YES;
  122. if (self.imageProgressUpdateBlock) {
  123. self.imageProgressUpdateBlock(1);
  124. }
  125. } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  126. _progressView.hidden = NO;
  127. [self bringSubviewToFront:_progressView];
  128. progress = progress > 0.02 ? progress : 0.02;;
  129. _progressView.progress = progress;
  130. if (self.imageProgressUpdateBlock) {
  131. self.imageProgressUpdateBlock(progress);
  132. }
  133. } networkAccessAllowed:YES];
  134. }
  135. - (void)recoverSubviews {
  136. [_scrollView setZoomScale:1.0 animated:NO];
  137. [self resizeSubviews];
  138. }
  139. - (void)resizeSubviews {
  140. _imageContainerView.tz_origin = CGPointZero;
  141. _imageContainerView.tz_width = self.scrollView.tz_width;
  142. UIImage *image = _imageView.image;
  143. if (image.size.height / image.size.width > self.tz_height / self.scrollView.tz_width) {
  144. _imageContainerView.tz_height = floor(image.size.height / (image.size.width / self.scrollView.tz_width));
  145. } else {
  146. CGFloat height = image.size.height / image.size.width * self.scrollView.tz_width;
  147. if (height < 1 || isnan(height)) height = self.tz_height;
  148. height = floor(height);
  149. _imageContainerView.tz_height = height;
  150. _imageContainerView.tz_centerY = self.tz_height / 2;
  151. }
  152. if (_imageContainerView.tz_height > self.tz_height && _imageContainerView.tz_height - self.tz_height <= 1) {
  153. _imageContainerView.tz_height = self.tz_height;
  154. }
  155. CGFloat contentSizeH = MAX(_imageContainerView.tz_height, self.tz_height);
  156. _scrollView.contentSize = CGSizeMake(self.scrollView.tz_width, contentSizeH);
  157. [_scrollView scrollRectToVisible:self.bounds animated:NO];
  158. _scrollView.alwaysBounceVertical = _imageContainerView.tz_height <= self.tz_height ? NO : YES;
  159. _imageView.frame = _imageContainerView.bounds;
  160. [self refreshScrollViewContentSize];
  161. }
  162. - (void)setAllowCrop:(BOOL)allowCrop {
  163. _allowCrop = allowCrop;
  164. _scrollView.maximumZoomScale = allowCrop ? 4.0 : 2.5;
  165. }
  166. - (void)refreshScrollViewContentSize {
  167. if (_allowCrop) {
  168. // 1.7.2 如果允许裁剪,需要让图片的任意部分都能在裁剪框内,于是对_scrollView做了如下处理:
  169. // 1.让contentSize增大(裁剪框右下角的图片部分)
  170. CGFloat contentWidthAdd = self.scrollView.tz_width - CGRectGetMaxX(_cropRect);
  171. CGFloat contentHeightAdd = (MIN(_imageContainerView.tz_height, self.tz_height) - self.cropRect.size.height) / 2;
  172. CGFloat newSizeW = self.scrollView.contentSize.width + contentWidthAdd;
  173. CGFloat newSizeH = MAX(self.scrollView.contentSize.height, self.tz_height) + contentHeightAdd;
  174. _scrollView.contentSize = CGSizeMake(newSizeW, newSizeH);
  175. _scrollView.alwaysBounceVertical = YES;
  176. // 2.让scrollView新增滑动区域(裁剪框左上角的图片部分)
  177. if (contentHeightAdd > 0) {
  178. _scrollView.contentInset = UIEdgeInsetsMake(contentHeightAdd, _cropRect.origin.x, 0, 0);
  179. } else {
  180. _scrollView.contentInset = UIEdgeInsetsZero;
  181. }
  182. }
  183. }
  184. #pragma mark - UITapGestureRecognizer Event
  185. - (void)doubleTap:(UITapGestureRecognizer *)tap {
  186. if (_scrollView.zoomScale > 1.0) {
  187. _scrollView.contentInset = UIEdgeInsetsZero;
  188. [_scrollView setZoomScale:1.0 animated:YES];
  189. } else {
  190. CGPoint touchPoint = [tap locationInView:self.imageView];
  191. CGFloat newZoomScale = _scrollView.maximumZoomScale;
  192. CGFloat xsize = self.frame.size.width / newZoomScale;
  193. CGFloat ysize = self.frame.size.height / newZoomScale;
  194. [_scrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES];
  195. }
  196. }
  197. - (void)singleTap:(UITapGestureRecognizer *)tap {
  198. if (self.singleTapGestureBlock) {
  199. self.singleTapGestureBlock();
  200. }
  201. }
  202. #pragma mark - UIScrollViewDelegate
  203. - (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  204. return _imageContainerView;
  205. }
  206. - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
  207. scrollView.contentInset = UIEdgeInsetsZero;
  208. }
  209. - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
  210. [self refreshImageContainerViewCenter];
  211. }
  212. - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
  213. [self refreshScrollViewContentSize];
  214. }
  215. #pragma mark - Private
  216. - (void)refreshImageContainerViewCenter {
  217. CGFloat offsetX = (_scrollView.tz_width > _scrollView.contentSize.width) ? ((_scrollView.tz_width - _scrollView.contentSize.width) * 0.5) : 0.0;
  218. CGFloat offsetY = (_scrollView.tz_height > _scrollView.contentSize.height) ? ((_scrollView.tz_height - _scrollView.contentSize.height) * 0.5) : 0.0;
  219. self.imageContainerView.center = CGPointMake(_scrollView.contentSize.width * 0.5 + offsetX, _scrollView.contentSize.height * 0.5 + offsetY);
  220. }
  221. @end