MJPhotoBrowser.m 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. //
  2. // MJPhotoBrowser.m
  3. //
  4. // Created by mj on 13-3-4.
  5. // Copyright (c) 2013年 itcast. All rights reserved.
  6. #import <QuartzCore/QuartzCore.h>
  7. #import "MJPhotoBrowser.h"
  8. #import "MJPhoto.h"
  9. #import "MJPhotoView.h"
  10. #import "MJPhotoToolbar.h"
  11. #import "SDWebImageManager.h"
  12. #define kPadding 10
  13. #define kPhotoViewTagOffset 1000
  14. #define kPhotoViewIndex(photoView) ([photoView tag] - kPhotoViewTagOffset)
  15. @interface MJPhotoBrowser () <MJPhotoViewDelegate>
  16. {
  17. // 滚动的view
  18. UIScrollView *_photoScrollView;
  19. // 所有的图片view
  20. NSMutableSet *_visiblePhotoViews;
  21. NSMutableSet *_reusablePhotoViews;
  22. // 工具条
  23. MJPhotoToolbar *_toolbar;
  24. // BOOL disableLayoutSubviews
  25. // 一开始的状态栏
  26. BOOL _statusBarHiddenInited;
  27. }
  28. @end
  29. @implementation MJPhotoBrowser
  30. #pragma mark - Lifecycle
  31. - (void)loadView
  32. {
  33. _statusBarHiddenInited = [UIApplication sharedApplication].isStatusBarHidden;
  34. // 隐藏状态栏
  35. [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
  36. self.view = [[UIView alloc] init];
  37. self.view.frame = [UIScreen mainScreen].bounds;
  38. self.view.backgroundColor = [UIColor blackColor];
  39. }
  40. - (void)viewDidLoad
  41. {
  42. [super viewDidLoad];
  43. // 1.创建UIScrollView
  44. [self createScrollView];
  45. // 2.创建工具条
  46. [self createToolbar];
  47. }
  48. - (void)show
  49. {
  50. UIWindow *window = [UIApplication sharedApplication].keyWindow;
  51. [window addSubview:self.view];
  52. [window.rootViewController addChildViewController:self];
  53. if (_currentPhotoIndex == 0) {
  54. [self showPhotos];
  55. }
  56. }
  57. #pragma mark - 私有方法
  58. #pragma mark 创建工具条
  59. - (void)createToolbar
  60. {
  61. CGFloat barHeight = 44;
  62. CGFloat barY = self.view.frame.size.height - barHeight;
  63. _toolbar = [[MJPhotoToolbar alloc] init];
  64. _toolbar.frame = CGRectMake(0, barY, self.view.frame.size.width, barHeight);
  65. _toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
  66. _toolbar.photos = _photos;
  67. [self.view addSubview:_toolbar];
  68. [self updateTollbarState];
  69. }
  70. #pragma mark 创建UIScrollView
  71. - (void)createScrollView
  72. {
  73. CGRect frame = self.view.bounds;
  74. frame.origin.x -= kPadding;
  75. frame.size.width += (2 * kPadding);
  76. _photoScrollView = [[UIScrollView alloc] initWithFrame:frame];
  77. _photoScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  78. _photoScrollView.pagingEnabled = YES;
  79. _photoScrollView.delegate = self;
  80. _photoScrollView.showsHorizontalScrollIndicator = NO;
  81. _photoScrollView.showsVerticalScrollIndicator = NO;
  82. _photoScrollView.backgroundColor = [UIColor clearColor];
  83. _photoScrollView.contentSize = CGSizeMake(frame.size.width * _photos.count, 0);
  84. [self.view addSubview:_photoScrollView];
  85. _photoScrollView.contentOffset = CGPointMake(_currentPhotoIndex * frame.size.width, 0);
  86. }
  87. - (void)setPhotos:(NSArray *)photos
  88. {
  89. _photos = photos;
  90. if (photos.count > 1) {
  91. _visiblePhotoViews = [NSMutableSet set];
  92. _reusablePhotoViews = [NSMutableSet set];
  93. }
  94. for (int i = 0; i<_photos.count; i++) {
  95. MJPhoto *photo = _photos[i];
  96. photo.index = i;
  97. photo.firstShow = i == _currentPhotoIndex;
  98. }
  99. }
  100. #pragma mark 设置选中的图片
  101. - (void)setCurrentPhotoIndex:(NSUInteger)currentPhotoIndex
  102. {
  103. _currentPhotoIndex = currentPhotoIndex;
  104. for (int i = 0; i<_photos.count; i++) {
  105. MJPhoto *photo = _photos[i];
  106. photo.firstShow = i == currentPhotoIndex;
  107. }
  108. if ([self isViewLoaded]) {
  109. _photoScrollView.contentOffset = CGPointMake(_currentPhotoIndex * _photoScrollView.frame.size.width, 0);
  110. // 显示所有的相片
  111. [self showPhotos];
  112. }
  113. }
  114. #pragma mark - MJPhotoView代理
  115. - (void)photoViewSingleTap:(MJPhotoView *)photoView
  116. {
  117. [UIApplication sharedApplication].statusBarHidden = _statusBarHiddenInited;
  118. self.view.backgroundColor = [UIColor clearColor];
  119. // 移除工具条
  120. [_toolbar removeFromSuperview];
  121. }
  122. - (void)photoViewDidEndZoom:(MJPhotoView *)photoView
  123. {
  124. [self.view removeFromSuperview];
  125. [self removeFromParentViewController];
  126. }
  127. - (void)photoViewImageFinishLoad:(MJPhotoView *)photoView
  128. {
  129. _toolbar.currentPhotoIndex = _currentPhotoIndex;
  130. }
  131. #pragma mark 显示照片
  132. - (void)showPhotos
  133. {
  134. // 只有一张图片
  135. if (_photos.count == 1) {
  136. [self showPhotoViewAtIndex:0];
  137. return;
  138. }
  139. CGRect visibleBounds = _photoScrollView.bounds;
  140. int firstIndex = (int)floorf((CGRectGetMinX(visibleBounds)+kPadding*2) / CGRectGetWidth(visibleBounds));
  141. int lastIndex = (int)floorf((CGRectGetMaxX(visibleBounds)-kPadding*2-1) / CGRectGetWidth(visibleBounds));
  142. if (firstIndex < 0) firstIndex = 0;
  143. if (firstIndex >= _photos.count) firstIndex = _photos.count - 1;
  144. if (lastIndex < 0) lastIndex = 0;
  145. if (lastIndex >= _photos.count) lastIndex = _photos.count - 1;
  146. // 回收不再显示的ImageView
  147. NSInteger photoViewIndex;
  148. for (MJPhotoView *photoView in _visiblePhotoViews)
  149. {
  150. photoViewIndex = kPhotoViewIndex(photoView);
  151. if (photoViewIndex < firstIndex || photoViewIndex > lastIndex)
  152. {
  153. [_reusablePhotoViews addObject:photoView];
  154. [photoView removeFromSuperview];
  155. }
  156. }
  157. [_visiblePhotoViews minusSet:_reusablePhotoViews];
  158. while (_reusablePhotoViews.count > 2)
  159. {
  160. [_reusablePhotoViews removeObject:[_reusablePhotoViews anyObject]];
  161. }
  162. for (NSUInteger index = firstIndex; index <= lastIndex; index++)
  163. {
  164. if (![self isShowingPhotoViewAtIndex:index])
  165. {
  166. [self showPhotoViewAtIndex:index];
  167. }
  168. }
  169. }
  170. #pragma mark 显示一个图片view
  171. - (void)showPhotoViewAtIndex:(int)index
  172. {
  173. MJPhotoView *photoView = [self dequeueReusablePhotoView];
  174. if (!photoView) { // 添加新的图片view
  175. photoView = [[MJPhotoView alloc] init];
  176. photoView.photoViewDelegate = self;
  177. }
  178. // 调整当期页的frame
  179. CGRect bounds = _photoScrollView.bounds;
  180. CGRect photoViewFrame = bounds;
  181. photoViewFrame.size.width -= (2 * kPadding);
  182. photoViewFrame.origin.x = (bounds.size.width * index) + kPadding;
  183. photoView.tag = kPhotoViewTagOffset + index;
  184. MJPhoto *photo = _photos[index];
  185. photoView.frame = photoViewFrame;
  186. photoView.photo = photo;
  187. if( photo.image )
  188. {
  189. _toolbar.currentPhotoIndex = index;
  190. }
  191. [_visiblePhotoViews addObject:photoView];
  192. [_photoScrollView addSubview:photoView];
  193. [self loadImageNearIndex:index];
  194. }
  195. #pragma mark 加载index附近的图片
  196. - (void)loadImageNearIndex:(int)index
  197. {
  198. if (index > 0) {
  199. __block MJPhoto *photo = _photos[index - 1];
  200. [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:photo.url options:SDWebImageLowPriority|SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
  201. } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
  202. photo.image = image;
  203. }];
  204. }
  205. if (index < _photos.count - 1) {
  206. __block MJPhoto *photo = _photos[index + 1];
  207. [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:photo.url options:SDWebImageLowPriority|SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
  208. } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
  209. photo.image = image;
  210. }];
  211. }
  212. }
  213. #pragma mark index这页是否正在显示
  214. - (BOOL)isShowingPhotoViewAtIndex:(NSUInteger)index {
  215. for (MJPhotoView *photoView in _visiblePhotoViews) {
  216. if (kPhotoViewIndex(photoView) == index) {
  217. return YES;
  218. }
  219. }
  220. return NO;
  221. }
  222. #pragma mark 循环利用某个view
  223. - (MJPhotoView *)dequeueReusablePhotoView
  224. {
  225. MJPhotoView *photoView = [_reusablePhotoViews anyObject];
  226. if (photoView) {
  227. [_reusablePhotoViews removeObject:photoView];
  228. }
  229. return photoView;
  230. }
  231. #pragma mark 更新toolbar状态
  232. - (void)updateTollbarState
  233. {
  234. _currentPhotoIndex = _photoScrollView.contentOffset.x / _photoScrollView.frame.size.width;
  235. _toolbar.currentPhotoIndex = _currentPhotoIndex;
  236. }
  237. #pragma mark - UIScrollView Delegate
  238. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  239. [self showPhotos];
  240. [self updateTollbarState];
  241. }
  242. @end