MLMSegmentScroll.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. //
  2. // MLMSegmentScroll.m
  3. // MLMSegmentPage
  4. //
  5. // Created by my on 2017/2/6.
  6. // Copyright © 2017年 my. All rights reserved.
  7. //
  8. #import "MLMSegmentScroll.h"
  9. #import "SegmentPageHead.h"
  10. @interface MLMSegmentScroll () <NSCacheDelegate,UIScrollViewDelegate>
  11. {
  12. CGFloat start_offset_x;
  13. }
  14. @property (nonatomic, strong) NSCache *viewsCache;//存储页面(使用计数功能)
  15. @property (nonatomic, strong) NSMutableArray *viewsArray;
  16. @end
  17. @implementation MLMSegmentScroll
  18. #pragma mark - init Method
  19. - (instancetype)initWithFrame:(CGRect)frame vcOrViews:(NSArray *)sources {
  20. if (self = [super initWithFrame:frame]) {
  21. _viewsArray = [sources mutableCopy];
  22. [self defaultSet];
  23. }
  24. return self;
  25. }
  26. #pragma mark - default setting
  27. - (void)defaultSet {
  28. WEAK(weakSelf, self)
  29. self.showsVerticalScrollIndicator = NO;
  30. self.showsHorizontalScrollIndicator = NO;
  31. self.pagingEnabled = YES;
  32. self.bounces = NO;
  33. self.delegate = weakSelf;
  34. [self setContentSize:CGSizeMake(_viewsArray.count *self.width, self.height)];
  35. _countLimit = _viewsArray.count;
  36. }
  37. #pragma mark - viewsCache
  38. - (NSCache *)viewsCache {
  39. if (!_viewsCache) {
  40. WEAK(weakSelf, self)
  41. _viewsCache = [[NSCache alloc] init];
  42. _viewsCache.countLimit = _countLimit;
  43. _viewsCache.delegate = weakSelf;
  44. _viewsCache.evictsObjectsWithDiscardedContent = YES;
  45. }
  46. return _viewsCache;
  47. }
  48. #pragma mark - default add View
  49. - (void)createView {
  50. _showIndex = MIN(_viewsArray.count-1, MAX(0, _showIndex));
  51. [self setContentOffset:CGPointMake(_showIndex * self.frame.size.width, 0)];
  52. if (_loadAll) {
  53. NSInteger startIndex;
  54. if (_viewsArray.count-_showIndex > _countLimit) {
  55. startIndex = _showIndex;
  56. } else {
  57. startIndex = _viewsArray.count - _countLimit;
  58. }
  59. for (NSInteger i = startIndex; i < startIndex + _countLimit; i ++) {
  60. [self addViewCacheIndex:i];
  61. }
  62. } else {
  63. [self setContentOffset:CGPointMake(_showIndex*self.width, 0) animated:NO];
  64. }
  65. }
  66. #pragma mark - changeSource
  67. - (void)changeSource:(NSArray *)sources {
  68. _viewsArray = [sources mutableCopy];
  69. _countLimit = MIN(_countLimit, _viewsArray.count);
  70. self.viewsCache.countLimit = _countLimit;
  71. [self.viewsCache removeAllObjects];
  72. [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
  73. [self setContentSize:CGSizeMake(_viewsArray.count *self.width, self.height)];
  74. [self createView];
  75. }
  76. //- (void)addVcOrViews:(NSArray *)sources {
  77. // NSInteger startIndex = _viewsArray.count;
  78. //
  79. // [_viewsArray addObjectsFromArray:sources];
  80. //
  81. // if (_loadAll) {
  82. // _viewsCache.countLimit = _viewsArray.count;
  83. // for (NSInteger i = startIndex; i < _viewsArray.count; i ++) {
  84. // [self addViewCacheIndex:i];
  85. // }
  86. // }
  87. // [self setContentSize:CGSizeMake(_viewsArray.count *self.width, self.height)];
  88. //}
  89. #pragma mark - addView
  90. - (void)addViewCacheIndex:(NSInteger)index {
  91. id object = _viewsArray[index];
  92. if ([object isKindOfClass:[NSString class]]) {
  93. Class class = NSClassFromString(object);
  94. if ([class isSubclassOfClass:[UIViewController class]]) {//vc
  95. UIViewController *vc = [class new];
  96. if (self.initSource) {
  97. self.initSource(vc, index);
  98. }
  99. [self addVC:vc atIndex:index];
  100. } else if ([class isSubclassOfClass:[UIView class]]){//view
  101. UIView *view = [class new];
  102. if (self.initSource) {
  103. self.initSource(view, index);
  104. }
  105. [self addView:view atIndex:index];
  106. } else {
  107. NSLog(@"please enter the correct name of class!");
  108. }
  109. } else {
  110. if ([object isKindOfClass:[UIViewController class]]) {
  111. [self addVC:object atIndex:index];
  112. } else if ([object isKindOfClass:[UIView class]]) {
  113. [self addView:object atIndex:index];
  114. } else {
  115. NSLog(@"this class was not found!");
  116. }
  117. }
  118. }
  119. #pragma mark - addvc
  120. - (void)addVC:(UIViewController *)vc atIndex:(NSInteger)index {
  121. NSLog(@"add - %@",@(index));
  122. if (![self.viewsCache objectForKey:@(index)]) {
  123. [self.viewsCache setObject:vc forKey:@(index)];
  124. }
  125. vc.view.frame = CGRectMake(index*self.width, 0, self.width, self.height);
  126. [self.viewController addChildViewController:vc];
  127. [self addSubview:vc.view];
  128. }
  129. #pragma mark - addview
  130. - (void)addView:(UIView *)view atIndex:(NSInteger)index {
  131. if (![self.viewsCache objectForKey:@(index)]) {
  132. [self.viewsCache setObject:view forKey:@(index)];
  133. }
  134. view.frame = CGRectMake(index*self.width, 0, self.width, self.height);
  135. [self addSubview:view];
  136. }
  137. - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
  138. [super setContentOffset:contentOffset animated:animated];
  139. NSInteger currentIndex = contentOffset.x/self.frame.size.width;
  140. if (!animated) {
  141. if ([self.segDelegate respondsToSelector:@selector(animationEndIndex:)]) {
  142. [self.segDelegate animationEndIndex:currentIndex];
  143. } else if (self.animationEnd) {
  144. self.animationEnd(currentIndex);
  145. }
  146. }
  147. if (![_viewsCache objectForKey:@(currentIndex)]) {
  148. [self addViewCacheIndex:currentIndex];
  149. }
  150. }
  151. #pragma mark - scrollDelegate
  152. -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
  153. start_offset_x = scrollView.contentOffset.x;
  154. }
  155. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  156. CGFloat scale = self.contentOffset.x/self.contentSize.width;
  157. if ([self.segDelegate respondsToSelector:@selector(scrollOffsetScale:)]) {
  158. [self.segDelegate scrollOffsetScale:scale];
  159. } else if (self.offsetScale) {
  160. self.offsetScale(scale);
  161. }
  162. if (_addTiming == SegmentAddScale) {
  163. NSInteger currentIndex = self.contentOffset.x/self.frame.size.width;
  164. BOOL left = start_offset_x>=self.contentOffset.x;
  165. NSInteger next_index = MAX(MIN(_viewsArray.count-1, left?currentIndex:currentIndex+1), 0);
  166. if (fabs(scale*_viewsArray.count-next_index)<(1-_addScale)) {
  167. if (![_viewsCache objectForKey:@(next_index)]) {
  168. [self addViewCacheIndex:next_index];
  169. }
  170. }
  171. }
  172. }
  173. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
  174. //滑动结束
  175. NSInteger currentIndex = self.contentOffset.x/self.frame.size.width;
  176. if ([self.segDelegate respondsToSelector:@selector(scrollEndIndex:)]) {
  177. [self.segDelegate scrollEndIndex:currentIndex];
  178. } else if (self.scrollEnd) {
  179. self.scrollEnd(currentIndex);
  180. }
  181. CGFloat scale = self.contentOffset.x/self.contentSize.width;
  182. if ([self.segDelegate respondsToSelector:@selector(scrollOffsetScale:)]) {
  183. [self.segDelegate scrollOffsetScale:scale];
  184. } else if (self.offsetScale) {
  185. self.offsetScale(scale);
  186. }
  187. if (_addTiming == SegmentAddNormal) {
  188. if (![_viewsCache objectForKey:@(currentIndex)]) {
  189. [self addViewCacheIndex:currentIndex];
  190. }
  191. }
  192. }
  193. - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
  194. //动画结束
  195. NSInteger currentIndex = self.contentOffset.x/self.frame.size.width;
  196. if ([self.segDelegate respondsToSelector:@selector(animationEndIndex:)]) {
  197. [self.segDelegate animationEndIndex:currentIndex];
  198. } else if (self.animationEnd) {
  199. self.animationEnd(currentIndex);
  200. }
  201. }
  202. #pragma mark - NSCacheDelegate
  203. -(void)cache:(NSCache *)cache willEvictObject:(id)obj {
  204. // dispatch_async(dispatch_get_main_queue(), ^{
  205. // //进入后台不清理
  206. // if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
  207. // return;
  208. // }
  209. // if (self.subviews.count > self.countLimit) {
  210. // if ([obj isKindOfClass:[UIViewController class]]) {
  211. // UIViewController *vc = obj;
  212. // [vc.view removeFromSuperview];
  213. // vc.view = nil;
  214. // [vc removeFromParentViewController];
  215. // } else {
  216. // UIView *vw = obj;
  217. // [vw removeFromSuperview];
  218. // vw = nil;
  219. // }
  220. // }
  221. // });
  222. }
  223. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
  224. if (self.contentOffset.x <= 0) {
  225. if ([otherGestureRecognizer.delegate isKindOfClass:NSClassFromString(@"_FDFullscreenPopGestureRecognizerDelegate")]) {
  226. return YES;
  227. }
  228. }
  229. // NSLog(@"contentOffset:%@\n contentSize:%@", NSStringFromCGPoint(self.contentOffset), NSStringFromCGSize(self.contentSize));
  230. if (self.contentOffset.x == (self.contentSize.width-self.f_width)) {
  231. return YES;
  232. }
  233. return NO;
  234. }
  235. - (NSInteger)currentIndex {
  236. return self.contentOffset.x/self.frame.size.width;
  237. }
  238. - (id)currentVcOrView {
  239. NSInteger index = [self currentIndex];
  240. id current = [self.viewsCache objectForKey:@(index)];
  241. if (!current) {
  242. current = self.viewsArray[index];
  243. }
  244. return current;
  245. }
  246. #pragma mark - dealloc
  247. - (void)dealloc {
  248. self.delegate = nil;
  249. [_viewsCache removeAllObjects];
  250. _viewsCache.delegate = nil;
  251. _viewsCache = nil;
  252. }
  253. @end