NTESPageView.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //
  2. // NTESPageView.m
  3. // NIM
  4. //
  5. // Created by chris on 15/12/16.
  6. // Copyright © 2015年 Netease. All rights reserved.
  7. //
  8. #import "NTESPageView.h"
  9. @interface NTESPageScrollView : UIScrollView
  10. @end
  11. @interface NTESPageView ()
  12. {
  13. NSInteger _currentPage;
  14. NSInteger _currentPageForRotation;
  15. }
  16. @property (nonatomic,strong) NSMutableArray *pages;
  17. - (void)setupControls;
  18. //重新载入的流程
  19. - (void)calculatePageNumbers;
  20. - (void)reloadPage;
  21. - (void)raisePageIndexChangedDelegate;
  22. @end
  23. @implementation NTESPageView
  24. - (id)initWithFrame:(CGRect)frame
  25. {
  26. self = [super initWithFrame:frame];
  27. if (self)
  28. {
  29. [self setupControls];
  30. }
  31. return self;
  32. }
  33. - (id)initWithCoder:(NSCoder *)aDecoder
  34. {
  35. if (self = [super initWithCoder:aDecoder])
  36. {
  37. [self setupControls];
  38. }
  39. return self;
  40. }
  41. - (void)setFrame:(CGRect)frame{
  42. CGFloat originalWidth = self.frame.size.width;
  43. [super setFrame:frame];
  44. if (originalWidth != frame.size.width) {
  45. [self reloadData];
  46. }
  47. }
  48. - (void)dealloc
  49. {
  50. _scrollView.delegate = nil;
  51. }
  52. - (void)layoutSubviews
  53. {
  54. [super layoutSubviews];
  55. [_scrollView setFrame:self.bounds];
  56. CGSize size = self.bounds.size;
  57. [self.scrollView setContentSize:CGSizeMake(size.width * [self.pages count], size.height)];
  58. for (NSInteger i = 0; i < [self.pages count]; i++)
  59. {
  60. id obj = [self.pages objectAtIndex:i];
  61. if ([obj isKindOfClass:[UIView class]])
  62. {
  63. [(UIView *)obj setFrame:CGRectMake(size.width * i, 0, size.width, size.height)];
  64. }
  65. }
  66. //CGSize size = self.bounds.size;
  67. BOOL animation = NO;
  68. if (self.pageViewDelegate && [self.pageViewDelegate respondsToSelector:@selector(needScrollAnimation)])
  69. {
  70. animation = [self.pageViewDelegate needScrollAnimation];
  71. }
  72. [self.scrollView scrollRectToVisible:CGRectMake(_currentPage * size.width, 0, size.width, size.height)
  73. animated:animation];
  74. }
  75. - (void)setupControls
  76. {
  77. if (_scrollView == nil)
  78. {
  79. _scrollView = [[NTESPageScrollView alloc]initWithFrame:self.bounds];
  80. _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  81. [self addSubview:_scrollView];
  82. _scrollView.pagingEnabled = YES;
  83. _scrollView.showsVerticalScrollIndicator = NO;
  84. _scrollView.showsHorizontalScrollIndicator = NO;
  85. _scrollView.delegate = self;
  86. _scrollView.scrollsToTop = NO;
  87. }
  88. }
  89. #pragma mark - 对外接口
  90. - (void)scrollToPage: (NSInteger)page
  91. {
  92. if (_currentPage != page || page == 0)
  93. {
  94. _currentPage = page;
  95. [self reloadData];
  96. }
  97. }
  98. - (void)reloadData
  99. {
  100. [self calculatePageNumbers];
  101. [self reloadPage];
  102. }
  103. - (UIView *)viewAtIndex: (NSInteger)index
  104. {
  105. UIView *view = nil;
  106. if (index >= 0 && index < [_pages count])
  107. {
  108. id obj = [_pages objectAtIndex:index];
  109. if ([obj isKindOfClass:[UIView class]])
  110. {
  111. view = obj;
  112. }
  113. }
  114. return view;
  115. }
  116. - (NSInteger)currentPage
  117. {
  118. return _currentPage;
  119. }
  120. - (NSInteger)pageInBound:(NSInteger)value min:(NSInteger)min max:(NSInteger)max{
  121. if (max < min) {
  122. max = min;
  123. }
  124. NSInteger bounded = value;
  125. if (bounded > max) {
  126. bounded = max;
  127. }
  128. if (bounded < min) {
  129. bounded = min;
  130. }
  131. return bounded;
  132. }
  133. #pragma mark - Page载入和销毁
  134. - (void)loadPagesForCurrentPage:(NSInteger)currentPage
  135. {
  136. NSUInteger count = [_pages count];
  137. if (count == 0)
  138. {
  139. return;
  140. }
  141. NSInteger first = [self pageInBound:currentPage - 1 min:0 max:count - 1];
  142. NSInteger last = [self pageInBound:currentPage + 1 min:0 max:count - 1];
  143. NSRange range = NSMakeRange(first, last - first + 1);
  144. for (NSUInteger index = 0; index < count; index++)
  145. {
  146. if (NSLocationInRange(index, range))
  147. {
  148. id obj = [_pages objectAtIndex:index];
  149. if (![obj isKindOfClass:[UIView class]])
  150. {
  151. if (_dataSource && [_dataSource respondsToSelector:@selector(pageView:viewInPage:)])
  152. {
  153. UIView *view = [_dataSource pageView:self viewInPage:index];
  154. [_pages replaceObjectAtIndex:index withObject:view];
  155. [self.scrollView addSubview:view];
  156. CGSize size = self.bounds.size;
  157. [view setFrame:CGRectMake(size.width * index, 0, size.width, size.height)];
  158. }
  159. else
  160. {
  161. assert(0);
  162. }
  163. }
  164. }
  165. else
  166. {
  167. id obj = [_pages objectAtIndex:index];
  168. if ([obj isKindOfClass:[UIView class]])
  169. {
  170. [obj removeFromSuperview];
  171. [_pages replaceObjectAtIndex:index withObject:[NSNull null]];
  172. }
  173. }
  174. }
  175. }
  176. - (void)calculatePageNumbers
  177. {
  178. NSInteger numberOfPages = 0;
  179. for (id obj in _pages)
  180. {
  181. if ([obj isKindOfClass:[UIView class]])
  182. {
  183. [(UIView *)obj removeFromSuperview];
  184. }
  185. }
  186. if(_dataSource && [_dataSource respondsToSelector:@selector(numberOfPages:)])
  187. {
  188. numberOfPages = [_dataSource numberOfPages:self];
  189. }
  190. self.pages = [NSMutableArray arrayWithCapacity:numberOfPages];
  191. for (NSInteger i = 0; i < numberOfPages; i ++)
  192. {
  193. [_pages addObject:[NSNull null]];
  194. }
  195. //注意,这里设置delegate是因为计算contentsize的时候会引起scrollViewDidScroll执行,修改currentpage的值,这样在贴图(举个例子)前面的分类页数比后面的分类页数多,前面的分类滚动到最后面一页后,再显示后面的分类,会显示不正确
  196. self.scrollView.delegate = nil;
  197. CGSize size = self.bounds.size;
  198. [self.scrollView setContentSize:CGSizeMake(size.width * numberOfPages, size.height)];
  199. self.scrollView.delegate = self;
  200. }
  201. - (void)reloadPage
  202. {
  203. //reload的时候尽量记住上次的位置
  204. if (_currentPage >= [_pages count])
  205. {
  206. _currentPage = [_pages count] - 1;
  207. }
  208. if (_currentPage < 0)
  209. {
  210. _currentPage = 0;
  211. }
  212. [self loadPagesForCurrentPage:_currentPage];
  213. [self raisePageIndexChangedDelegate];
  214. [self setNeedsLayout];
  215. }
  216. #pragma mark - ScrollView Delegate
  217. - (void)scrollViewDidScroll:(UIScrollView *)scrollView
  218. {
  219. CGFloat width = scrollView.bounds.size.width;
  220. CGFloat offsetX = scrollView.contentOffset.x;
  221. NSInteger page = (NSInteger)(fabs(offsetX / width));
  222. if (page >= 0 && page < [_pages count])
  223. {
  224. if (_currentPage == page) {
  225. return;
  226. }
  227. _currentPage = page;
  228. [self loadPagesForCurrentPage:_currentPage];
  229. }
  230. if (_pageViewDelegate && [_pageViewDelegate respondsToSelector:@selector(pageViewDidScroll:)])
  231. {
  232. [_pageViewDelegate pageViewDidScroll:self];
  233. }
  234. }
  235. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
  236. {
  237. [self raisePageIndexChangedDelegate];
  238. }
  239. #pragma mark - 辅助方法
  240. - (void)raisePageIndexChangedDelegate
  241. {
  242. if (_pageViewDelegate && [_pageViewDelegate respondsToSelector:@selector(pageViewScrollEnd:currentIndex:totolPages:)])
  243. {
  244. [_pageViewDelegate pageViewScrollEnd:self
  245. currentIndex:_currentPage
  246. totolPages:[_pages count]];
  247. }
  248. }
  249. - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
  250. duration:(NSTimeInterval)duration
  251. {
  252. _scrollView.delegate = nil;
  253. _currentPageForRotation = _currentPage;
  254. }
  255. - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
  256. duration:(NSTimeInterval)duration
  257. {
  258. CGSize size = self.bounds.size;
  259. _scrollView.contentSize = CGSizeMake(size.width * [_pages count], size.height);
  260. for (NSUInteger i = 0; i < [_pages count]; i++)
  261. {
  262. id obj = [_pages objectAtIndex:i];
  263. if ([obj isKindOfClass:[UIView class]])
  264. {
  265. [(UIView *)obj setFrame:CGRectMake(size.width * i, 0, size.width, size.height)];
  266. /*
  267. //这里有点ugly,先这样吧...
  268. if ([obj respondsToSelector:@selector(reset)])
  269. {
  270. [obj performSelector:@selector(reset)];
  271. }*/
  272. }
  273. }
  274. _scrollView.contentOffset = CGPointMake(_currentPageForRotation * self.bounds.size.width, 0);
  275. _scrollView.delegate = self;
  276. }
  277. @end
  278. @implementation NTESPageScrollView
  279. //fix: swipe to delete in a UITableView which is embeded in a UIScrollView
  280. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer
  281. {
  282. return [otherGestureRecognizer.view.superview isKindOfClass:[UITableView class]];
  283. }
  284. @end