MJPhotoBrowser.m 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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 <SDWebImagePrefetcher.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 blackColor];
  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. if (_photos.count == 0) {
  50. return;
  51. }
  52. UIWindow *window = [UIApplication sharedApplication].keyWindow;
  53. [window addSubview:self.view];
  54. [window.rootViewController addChildViewController:self];
  55. if (_currentPhotoIndex == 0) {
  56. [self showPhotos];
  57. }
  58. }
  59. #pragma mark - 私有方法
  60. #pragma mark 创建工具条
  61. - (void)createToolbar
  62. {
  63. CGFloat barHeight = 44;
  64. CGFloat barY = self.view.frame.size.height - barHeight - kNavOffSet;
  65. _toolbar = [[MJPhotoToolbar alloc] init];
  66. _toolbar.frame = CGRectMake(0, barY, self.view.frame.size.width, barHeight);
  67. _toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
  68. _toolbar.photos = _photos;
  69. [self.view addSubview:_toolbar];
  70. [self updateTollbarState];
  71. }
  72. #pragma mark 创建UIScrollView
  73. - (void)createScrollView
  74. {
  75. CGRect frame = self.view.bounds;
  76. frame.origin.x -= kPadding;
  77. frame.size.width += (2 * kPadding);
  78. _photoScrollView = [[UIScrollView alloc] initWithFrame:frame];
  79. _photoScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  80. _photoScrollView.pagingEnabled = YES;
  81. _photoScrollView.delegate = self;
  82. _photoScrollView.showsHorizontalScrollIndicator = NO;
  83. _photoScrollView.showsVerticalScrollIndicator = NO;
  84. _photoScrollView.backgroundColor = [UIColor clearColor];
  85. _photoScrollView.contentSize = CGSizeMake(frame.size.width * _photos.count, 0);
  86. [self.view addSubview:_photoScrollView];
  87. //danson
  88. //创建完scroll 先设置一个偏移量 调用scroll滑动方法 目的是保存按钮第一次有效
  89. //_photoScrollView.contentOffset = CGPointMake(5, 0);
  90. //上面的做法会使起始图片的现实产生问题 改成下面这种做法 估计会更好
  91. _photoScrollView.contentOffset = CGPointMake(_currentPhotoIndex * frame.size.width + 1, 0);
  92. }
  93. - (void)setPhotos:(NSArray *)photos
  94. {
  95. _photos = photos;
  96. if (photos.count > 1) {
  97. _visiblePhotoViews = [NSMutableSet set];
  98. _reusablePhotoViews = [NSMutableSet set];
  99. }
  100. for (int i = 0; i<_photos.count; i++) {
  101. MJPhoto *photo = _photos[i];
  102. photo.index = i;
  103. photo.firstShow = i == _currentPhotoIndex;
  104. }
  105. }
  106. #pragma mark 设置选中的图片
  107. - (void)setCurrentPhotoIndex:(NSUInteger)currentPhotoIndex
  108. {
  109. _currentPhotoIndex = currentPhotoIndex;
  110. //这样不是更方便 好吧 这样会有很多firstShow
  111. // MJPhoto *photo = _photos[currentPhotoIndex];
  112. // photo.firstShow = YES;
  113. for (int i = 0; i<_photos.count; i++) {
  114. MJPhoto *photo = _photos[i];
  115. photo.firstShow = i == currentPhotoIndex ? YES : NO;
  116. }
  117. if ([self isViewLoaded]) {
  118. _photoScrollView.contentOffset = CGPointMake(_currentPhotoIndex * _photoScrollView.frame.size.width, 0);
  119. // 显示所有的相片
  120. [self showPhotos];
  121. }
  122. }
  123. #pragma mark - MJPhotoView代理
  124. - (void)photoViewSingleTap:(MJPhotoView *)photoView
  125. {
  126. [UIApplication sharedApplication].statusBarHidden = _statusBarHiddenInited;
  127. // 移除工具条
  128. [_toolbar removeFromSuperview];
  129. }
  130. - (void)photoViewDidEndZoom:(MJPhotoView *)photoView
  131. {
  132. self.view.backgroundColor = [UIColor clearColor];
  133. [self.view removeFromSuperview];
  134. [self removeFromParentViewController];
  135. }
  136. - (void)photoViewImageFinishLoad:(MJPhotoView *)photoView
  137. {
  138. _toolbar.currentPhotoIndex = _currentPhotoIndex;
  139. }
  140. #pragma mark 显示照片
  141. - (void)showPhotos
  142. {
  143. // if ([self isViewLoaded]) {
  144. // _photoScrollView.contentOffset = CGPointMake(_currentPhotoIndex * _photoScrollView.frame.size.width, 0);
  145. // }
  146. // 只有一张图片
  147. if (_photos.count == 1) {
  148. //danson
  149. //scroll代理方法调了3次 为了不添加重复的scroll 做个判断
  150. //NSLog(@"%d",(int)_photoScrollView.subviews.count);
  151. if (_photoScrollView.subviews.count == 0) {
  152. [self showPhotoViewAtIndex:0];
  153. }
  154. return;
  155. }
  156. CGRect visibleBounds = _photoScrollView.bounds;
  157. int firstIndex = (int)floorf((CGRectGetMinX(visibleBounds)+kPadding*2) / CGRectGetWidth(visibleBounds));
  158. int lastIndex = (int)floorf((CGRectGetMaxX(visibleBounds)-kPadding*2-1) / CGRectGetWidth(visibleBounds));
  159. if (firstIndex < 0) firstIndex = 0;
  160. if (firstIndex >= _photos.count) firstIndex = (int)_photos.count - 1;
  161. if (lastIndex < 0) lastIndex = 0;
  162. if (lastIndex >= _photos.count) lastIndex = (int)_photos.count - 1;
  163. // 回收不再显示的ImageView
  164. NSInteger photoViewIndex;
  165. for (MJPhotoView *photoView in _visiblePhotoViews) {
  166. photoViewIndex = kPhotoViewIndex(photoView);
  167. if (photoViewIndex < firstIndex || photoViewIndex > lastIndex) {
  168. [_reusablePhotoViews addObject:photoView];
  169. [photoView removeFromSuperview];
  170. }
  171. }
  172. [_visiblePhotoViews minusSet:_reusablePhotoViews];
  173. while (_reusablePhotoViews.count > 2) {
  174. [_reusablePhotoViews removeObject:[_reusablePhotoViews anyObject]];
  175. }
  176. for (NSUInteger index = firstIndex; index <= lastIndex; index++) {
  177. if (![self isShowingPhotoViewAtIndex:index]) {
  178. [self showPhotoViewAtIndex:(int)index];
  179. }
  180. }
  181. }
  182. #pragma mark 显示一个图片view
  183. - (void)showPhotoViewAtIndex:(int)index
  184. {
  185. //先移除
  186. MJPhotoView *photoView = [self dequeueReusablePhotoView];
  187. if (!photoView) { // 添加新的图片view
  188. photoView = [[MJPhotoView alloc] init];
  189. photoView.photoViewDelegate = self;
  190. }
  191. // 调整当前页的frame
  192. CGRect bounds = _photoScrollView.bounds;
  193. CGRect photoViewFrame = bounds;
  194. photoViewFrame.size.width -= (2 * kPadding);
  195. photoViewFrame.origin.x = (bounds.size.width * index) + kPadding;
  196. photoView.tag = kPhotoViewTagOffset + index;
  197. MJPhoto *photo = _photos[index];
  198. photoView.frame = photoViewFrame;
  199. photoView.photo = photo;
  200. [_visiblePhotoViews addObject:photoView];
  201. [_photoScrollView addSubview:photoView];
  202. [self loadImageNearIndex:index];
  203. }
  204. #pragma mark 加载index附近的图片
  205. - (void)loadImageNearIndex:(int)index
  206. {
  207. if (index > 0) {
  208. MJPhoto *photo = _photos[index - 1];
  209. [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:@[photo.url]];
  210. }
  211. if (index < _photos.count - 1) {
  212. MJPhoto *photo = _photos[index + 1];
  213. [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:@[photo.url]];
  214. }
  215. }
  216. #pragma mark index这页是否正在显示
  217. - (BOOL)isShowingPhotoViewAtIndex:(NSUInteger)index {
  218. for (MJPhotoView *photoView in _visiblePhotoViews) {
  219. if (kPhotoViewIndex(photoView) == index) {
  220. return YES;
  221. }
  222. }
  223. return NO;
  224. }
  225. #pragma mark 循环利用某个view
  226. - (MJPhotoView *)dequeueReusablePhotoView
  227. {
  228. MJPhotoView *photoView = [_reusablePhotoViews anyObject];
  229. if (photoView) {
  230. [_reusablePhotoViews removeObject:photoView];
  231. }
  232. return photoView;
  233. }
  234. #pragma mark 更新toolbar状态
  235. - (void)updateTollbarState
  236. {
  237. _currentPhotoIndex = _photoScrollView.contentOffset.x / _photoScrollView.frame.size.width;
  238. _toolbar.currentPhotoIndex = _currentPhotoIndex;
  239. }
  240. #pragma mark - UIScrollView Delegate
  241. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  242. //NSLog(@"scroll代理");
  243. [self showPhotos];
  244. [self updateTollbarState];
  245. }
  246. @end