MJPhotoBrowser.m 7.5 KB

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