SDPhotoBrowser.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //
  2. // SDPhotoBrowser.m
  3. // photobrowser
  4. //
  5. // Created by aier on 15-2-3.
  6. // Copyright (c) 2015年 aier. All rights reserved.
  7. //
  8. #import "SDPhotoBrowser.h"
  9. #import "UIImageView+WebCache.h"
  10. #import "SDBrowserImageView.h"
  11. #import "YHActionSheet.h"
  12. // ============在这里方便配置样式相关设置===========
  13. // ||
  14. // ||
  15. // ||
  16. // \\//
  17. // \/
  18. #import "SDPhotoBrowserConfig.h"
  19. // =============================================
  20. @implementation SDPhotoBrowser
  21. {
  22. UIScrollView *_scrollView;
  23. BOOL _hasShowedFistView;
  24. // UILabel *_indexLabel;//暂时pageControl代替
  25. UIPageControl *_pageControl;
  26. // UIButton *_saveButton;
  27. UIActivityIndicatorView *_indicatorView;
  28. BOOL _willDisappear;
  29. }
  30. - (id)initWithFrame:(CGRect)frame
  31. {
  32. self = [super initWithFrame:frame];
  33. if (self) {
  34. self.backgroundColor = SDPhotoBrowserBackgrounColor;
  35. }
  36. return self;
  37. }
  38. #pragma mark - Life
  39. - (void)didMoveToSuperview
  40. {
  41. [self setupScrollView];
  42. [self setupToolbars];
  43. }
  44. - (void)setupScrollView
  45. {
  46. _scrollView = [[UIScrollView alloc] init];
  47. _scrollView.delegate = self;
  48. _scrollView.showsHorizontalScrollIndicator = NO;
  49. _scrollView.showsVerticalScrollIndicator = NO;
  50. _scrollView.pagingEnabled = YES;
  51. [self addSubview:_scrollView];
  52. for (int i = 0; i < self.imageCount; i++) {
  53. SDBrowserImageView *imageView = [[SDBrowserImageView alloc] init];
  54. imageView.tag = i;
  55. // 单击图片
  56. UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(photoClick:)];
  57. // 双击放大图片
  58. UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewDoubleTaped:)];
  59. doubleTap.numberOfTapsRequired = 2;
  60. UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewLongPressed:)];
  61. [singleTap requireGestureRecognizerToFail:doubleTap];
  62. [imageView addGestureRecognizer:singleTap];
  63. [imageView addGestureRecognizer:doubleTap];
  64. [imageView addGestureRecognizer:longPress];
  65. [_scrollView addSubview:imageView];
  66. }
  67. [self setupImageOfImageViewForIndex:self.currentImageIndex];
  68. }
  69. - (void)dealloc
  70. {
  71. [[UIApplication sharedApplication].keyWindow removeObserver:self forKeyPath:@"frame"];
  72. }
  73. - (void)layoutSubviews
  74. {
  75. [super layoutSubviews];
  76. CGRect rect = self.bounds;
  77. rect.size.width += SDPhotoBrowserImageViewMargin * 2;
  78. _scrollView.bounds = rect;
  79. _scrollView.center = self.center;
  80. CGFloat y = 0;
  81. CGFloat w = _scrollView.frame.size.width - SDPhotoBrowserImageViewMargin * 2;
  82. CGFloat h = _scrollView.frame.size.height;
  83. [_scrollView.subviews enumerateObjectsUsingBlock:^(SDBrowserImageView *obj, NSUInteger idx, BOOL *stop) {
  84. CGFloat x = SDPhotoBrowserImageViewMargin + idx * (SDPhotoBrowserImageViewMargin * 2 + w);
  85. obj.frame = CGRectMake(x, y, w, h);
  86. }];
  87. _scrollView.contentSize = CGSizeMake(_scrollView.subviews.count * _scrollView.frame.size.width, 0);
  88. _scrollView.contentOffset = CGPointMake(self.currentImageIndex * _scrollView.frame.size.width, 0);
  89. if (!_hasShowedFistView) {
  90. [self showFirstImage];
  91. }
  92. // _indexLabel.center = CGPointMake(self.bounds.size.width * 0.5, 35);
  93. // _saveButton.frame = CGRectMake(10, self.bounds.size.height - 50, 50, 25);
  94. }
  95. //是否已缓存原图
  96. - (BOOL)hasHighQImage{
  97. SDWebImageManager *manager = [SDWebImageManager sharedManager];
  98. // [manager cacheKeyForURL:<#(nullable NSURL *)#>]
  99. // [manager diskImageExistsForURL:[self highQualityImageURLForIndex:self.currentImageIndex] completion:^(BOOL isInCache) {
  100. //
  101. // }];
  102. // BOOL hasHighQImage = [manager diskImageExistsForURL:[self highQualityImageURLForIndex:self.currentImageIndex]];
  103. // return hasHighQImage;
  104. return NO;
  105. }
  106. //显示原图
  107. - (void)showOriImage{
  108. UIView *sourceView = self.sourceImagesContainerView.subviews[self.currentImageIndex];
  109. CGRect rect = [self.sourceImagesContainerView convertRect:sourceView.frame toView:self];
  110. UIImageView *tempView = [[UIImageView alloc] init];
  111. tempView.image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:[self highQualityImageURLForIndex:self.currentImageIndex].absoluteString];
  112. [self addSubview:tempView];
  113. CGRect targetTemp = _scrollView.subviews[self.currentImageIndex].bounds;
  114. tempView.frame = rect;
  115. tempView.contentMode = [_scrollView.subviews[self.currentImageIndex] contentMode];
  116. _scrollView.hidden = YES;
  117. [UIView animateWithDuration:SDPhotoBrowserShowImageAnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
  118. tempView.center = self.center;
  119. tempView.bounds = (CGRect){CGPointZero, targetTemp.size};
  120. } completion:^(BOOL finished) {
  121. _hasShowedFistView = YES;
  122. [tempView removeFromSuperview];
  123. _scrollView.hidden = NO;
  124. }];
  125. }
  126. //显示缩略图
  127. - (void)showThumbImage{
  128. UIView *sourceView = self.sourceImagesContainerView.subviews[self.currentImageIndex];
  129. CGRect rect = [self.sourceImagesContainerView convertRect:sourceView.frame toView:self];
  130. UIImageView *tempView = [[UIImageView alloc] init];
  131. tempView.image = [self placeholderImageForIndex:self.currentImageIndex];
  132. [self addSubview:tempView];
  133. CGRect targetTemp = _scrollView.subviews[self.currentImageIndex].bounds;
  134. tempView.frame = rect;
  135. tempView.contentMode = [_scrollView.subviews[self.currentImageIndex] contentMode];
  136. _scrollView.hidden = YES;
  137. [UIView animateWithDuration:SDPhotoBrowserShowImageAnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
  138. tempView.center = self.center;
  139. tempView.bounds = (CGRect){CGPointZero, targetTemp.size};
  140. } completion:^(BOOL finished) {
  141. _hasShowedFistView = YES;
  142. [tempView removeFromSuperview];
  143. _scrollView.hidden = NO;
  144. }];
  145. }
  146. - (void)showFirstImage
  147. {
  148. if ([self hasHighQImage]) {
  149. [self showOriImage];
  150. }
  151. else{
  152. [self showThumbImage];
  153. }
  154. }
  155. - (void)setupToolbars
  156. {
  157. // 1. 序标
  158. // UILabel *indexLabel = [[UILabel alloc] init];
  159. // indexLabel.bounds = CGRectMake(0, 0, 80, 30);
  160. // indexLabel.textAlignment = NSTextAlignmentCenter;
  161. // indexLabel.textColor = [UIColor whiteColor];
  162. // indexLabel.font = [UIFont boldSystemFontOfSize:16];
  163. // indexLabel.clipsToBounds = YES;
  164. // if (self.imageCount > 1) {
  165. // indexLabel.text = [NSString stringWithFormat:@"1/%ld", (long)self.imageCount];
  166. // }
  167. // _indexLabel = indexLabel;
  168. // [self addSubview:indexLabel];
  169. if (self.imageCount > 1 )
  170. {
  171. UIPageControl *pCtrl = [[UIPageControl alloc] init];
  172. pCtrl.frame = CGRectMake((self.bounds.size.width-60)/2, self.bounds.size.height-30, 80, 30);
  173. pCtrl.numberOfPages = self.imageCount;
  174. [self addSubview:pCtrl];
  175. _pageControl = pCtrl;
  176. }
  177. // // 2.保存按钮
  178. // UIButton *saveButton = [[UIButton alloc] init];
  179. // [saveButton setTitle:ASLocalizedString(@"保存")forState:UIControlStateNormal];
  180. // [saveButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  181. // saveButton.clipsToBounds = YES;
  182. // [saveButton addTarget:self action:@selector(saveImage) forControlEvents:UIControlEventTouchUpInside];
  183. // saveButton.backgroundColor = kGreenColor;
  184. // saveButton.layer.cornerRadius = 3;
  185. // saveButton.layer.masksToBounds = YES;
  186. // _saveButton = saveButton;
  187. // [self addSubview:saveButton];
  188. }
  189. - (void)saveImage
  190. {
  191. int index = _scrollView.contentOffset.x / _scrollView.bounds.size.width;
  192. UIImageView *currentImageView = _scrollView.subviews[index];
  193. UIImageWriteToSavedPhotosAlbum(currentImageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
  194. UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] init];
  195. indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
  196. indicator.center = self.center;
  197. _indicatorView = indicator;
  198. [[UIApplication sharedApplication].keyWindow addSubview:indicator];
  199. [indicator startAnimating];
  200. }
  201. - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
  202. {
  203. [_indicatorView removeFromSuperview];
  204. UILabel *label = [[UILabel alloc] init];
  205. label.textColor = [UIColor whiteColor];
  206. label.backgroundColor = [UIColor colorWithRed:0.1f green:0.1f blue:0.1f alpha:0.90f];
  207. label.layer.cornerRadius = 5;
  208. label.clipsToBounds = YES;
  209. label.bounds = CGRectMake(0, 0, 150, 30);
  210. label.center = self.center;
  211. label.textAlignment = NSTextAlignmentCenter;
  212. label.font = [UIFont boldSystemFontOfSize:14];
  213. [[UIApplication sharedApplication].keyWindow addSubview:label];
  214. [[UIApplication sharedApplication].keyWindow bringSubviewToFront:label];
  215. if (error) {
  216. label.text = SDPhotoBrowserSaveImageFailText;
  217. } else {
  218. label.text = SDPhotoBrowserSaveImageSuccessText;
  219. }
  220. [label performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1.0];
  221. }
  222. #pragma mark - Gesture
  223. - (void)photoClick:(UITapGestureRecognizer *)recognizer
  224. {
  225. _scrollView.hidden = YES;
  226. _willDisappear = YES;
  227. SDBrowserImageView *currentImageView = (SDBrowserImageView *)recognizer.view;
  228. NSInteger currentIndex = currentImageView.tag;
  229. UIView *sourceView = self.sourceImagesContainerView.subviews[currentIndex];
  230. CGRect targetTemp = [self.sourceImagesContainerView convertRect:sourceView.frame toView:self];
  231. UIImageView *tempView = [[UIImageView alloc] init];
  232. tempView.contentMode = sourceView.contentMode;
  233. tempView.clipsToBounds = YES;
  234. tempView.image = currentImageView.image;
  235. CGFloat h = (self.bounds.size.width / currentImageView.image.size.width) * currentImageView.image.size.height;
  236. if (!currentImageView.image) { // 防止 因imageview的image加载失败 导致 崩溃
  237. h = self.bounds.size.height;
  238. }
  239. tempView.bounds = CGRectMake(0, 0, self.bounds.size.width, h);
  240. tempView.center = self.center;
  241. [self addSubview:tempView];
  242. // _saveButton.hidden = YES;
  243. [UIView animateWithDuration:SDPhotoBrowserHideImageAnimationDuration delay:0 options:UIViewAnimationOptionTransitionCurlUp animations:^{
  244. tempView.frame = targetTemp;
  245. self.backgroundColor = [UIColor clearColor];
  246. // _indexLabel.alpha = 0.1;
  247. } completion:^(BOOL finished) {
  248. [self removeFromSuperview];
  249. }];
  250. }
  251. - (void)imageViewDoubleTaped:(UITapGestureRecognizer *)recognizer
  252. {
  253. SDBrowserImageView *imageView = (SDBrowserImageView *)recognizer.view;
  254. CGFloat scale;
  255. if (imageView.isScaled) {
  256. scale = 1.0;
  257. } else {
  258. scale = 2.0;
  259. }
  260. SDBrowserImageView *view = (SDBrowserImageView *)recognizer.view;
  261. [view doubleTapToZommWithScale:scale];
  262. }
  263. - (void)imageViewLongPressed:(UILongPressGestureRecognizer *)gesture{
  264. if(gesture.state == UIGestureRecognizerStateBegan){
  265. __weak typeof(self)weakSelf = self;
  266. YHActionSheet *aSheet = [[YHActionSheet alloc] initWithCancelTitle:ASLocalizedString(@"取消")otherTitles:@[ASLocalizedString(@"保存图片")]];
  267. [aSheet dismissForCompletionHandle:^(NSInteger clickedIndex, BOOL isCancel) {
  268. if (!isCancel) {
  269. switch (clickedIndex) {
  270. case 0:
  271. NSLog(ASLocalizedString(@"保存图片"));
  272. [weakSelf saveImage];
  273. break;
  274. default:
  275. break;
  276. }
  277. }
  278. }];
  279. [aSheet show];
  280. }
  281. }
  282. #pragma mark - Public
  283. - (void)show
  284. {
  285. UIWindow *window = [UIApplication sharedApplication].keyWindow;
  286. self.frame = window.bounds;
  287. [window addObserver:self forKeyPath:@"frame" options:0 context:nil];
  288. [window addSubview:self];
  289. }
  290. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(UIView *)object change:(NSDictionary *)change context:(void *)context
  291. {
  292. if ([keyPath isEqualToString:@"frame"]) {
  293. self.frame = object.bounds;
  294. SDBrowserImageView *currentImageView = _scrollView.subviews[_currentImageIndex];
  295. if ([currentImageView isKindOfClass:[SDBrowserImageView class]]) {
  296. [currentImageView clear];
  297. }
  298. }
  299. }
  300. #pragma mark - Private
  301. - (UIImage *)placeholderImageForIndex:(NSInteger)index
  302. {
  303. if ([self.delegate respondsToSelector:@selector(photoBrowser:placeholderImageForIndex:)]) {
  304. return [self.delegate photoBrowser:self placeholderImageForIndex:index];
  305. }
  306. return nil;
  307. }
  308. - (NSURL *)highQualityImageURLForIndex:(NSInteger)index
  309. {
  310. if ([self.delegate respondsToSelector:@selector(photoBrowser:highQualityImageURLForIndex:)]) {
  311. return [self.delegate photoBrowser:self highQualityImageURLForIndex:index];
  312. }
  313. return nil;
  314. }
  315. // 加载图片
  316. - (void)setupImageOfImageViewForIndex:(NSInteger)index
  317. {
  318. SDBrowserImageView *imageView = _scrollView.subviews[index];
  319. self.currentImageIndex = index;
  320. if (imageView.hasLoadedImage) return;
  321. if ([self hasHighQImage]) {
  322. imageView.image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:[self highQualityImageURLForIndex:self.currentImageIndex].absoluteString];
  323. }
  324. else{
  325. if ([self highQualityImageURLForIndex:index]) {
  326. [imageView setImageWithURL:[self highQualityImageURLForIndex:index] placeholderImage:[self placeholderImageForIndex:index]];
  327. } else {
  328. imageView.image = [self placeholderImageForIndex:index];
  329. }
  330. }
  331. imageView.hasLoadedImage = YES;
  332. }
  333. #pragma mark - scrollview代理方法
  334. - (void)scrollViewDidScroll:(UIScrollView *)scrollView
  335. {
  336. int index = (scrollView.contentOffset.x + _scrollView.bounds.size.width * 0.5) / _scrollView.bounds.size.width;
  337. // 有过缩放的图片在拖动一定距离后清除缩放
  338. CGFloat margin = 150;
  339. CGFloat x = scrollView.contentOffset.x;
  340. CGFloat distance = x - index * _scrollView.bounds.size.width;
  341. if (distance > margin || distance < - margin) {
  342. SDBrowserImageView *imageView = _scrollView.subviews[index];
  343. if (imageView.isScaled) {
  344. [UIView animateWithDuration:0.5 animations:^{
  345. imageView.transform = CGAffineTransformIdentity;
  346. } completion:^(BOOL finished) {
  347. [imageView eliminateScale];
  348. }];
  349. }
  350. }
  351. if (!_willDisappear) {
  352. // _indexLabel.text = [NSString stringWithFormat:@"%d/%ld", index + 1, (long)self.imageCount];
  353. _pageControl.currentPage = index;
  354. }
  355. [self setupImageOfImageViewForIndex:index];
  356. }
  357. @end