MJPhotoBrowser.m 8.9 KB

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