TYPageControl.m 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. //
  2. // TYPageControl.m
  3. // TYCyclePagerViewDemo
  4. //
  5. // Created by tany on 2017/6/20.
  6. // Copyright © 2017年 tany. All rights reserved.
  7. //
  8. #import "TYPageControl.h"
  9. @interface TYPageControl ()
  10. // UI
  11. @property (nonatomic, strong) NSArray<UIImageView *> *indicatorViews;
  12. // Data
  13. @property (nonatomic, assign) BOOL forceUpdate;
  14. @end
  15. @implementation TYPageControl
  16. #pragma mark - life cycle
  17. - (instancetype)initWithFrame:(CGRect)frame {
  18. if (self = [super initWithFrame:frame]) {
  19. [self configurePropertys];
  20. }
  21. return self;
  22. }
  23. - (instancetype)initWithCoder:(NSCoder *)aDecoder {
  24. if (self = [super initWithCoder:aDecoder]) {
  25. [self configurePropertys];
  26. }
  27. return self;
  28. }
  29. - (void)configurePropertys {
  30. self.userInteractionEnabled = NO;
  31. _forceUpdate = NO;
  32. _animateDuring = 0.3;
  33. _pageIndicatorSpaing = 10;
  34. _indicatorImageContentMode = UIViewContentModeCenter;
  35. _pageIndicatorSize = CGSizeMake(6,6);
  36. _currentPageIndicatorSize = _pageIndicatorSize;
  37. _pageIndicatorTintColor = [UIColor colorWithRed:128/255. green:128/255. blue:128/255. alpha:1];
  38. _currentPageIndicatorTintColor = [UIColor whiteColor];
  39. }
  40. - (void)willMoveToSuperview:(UIView *)newSuperview {
  41. [super willMoveToSuperview:newSuperview];
  42. if (newSuperview) {
  43. _forceUpdate = YES;
  44. [self updateIndicatorViews];
  45. _forceUpdate = NO;
  46. }
  47. }
  48. #pragma mark - getter setter
  49. - (CGSize)contentSize {
  50. CGFloat width = (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _pageIndicatorSize.width + _contentInset.left +_contentInset.right;
  51. CGFloat height = _currentPageIndicatorSize.height + _contentInset.top + _contentInset.bottom;
  52. return CGSizeMake(width, height);
  53. }
  54. - (void)setNumberOfPages:(NSInteger)numberOfPages {
  55. if (numberOfPages == _numberOfPages) {
  56. return;
  57. }
  58. _numberOfPages = numberOfPages;
  59. if (_currentPage >= numberOfPages) {
  60. _currentPage = 0;
  61. }
  62. [self updateIndicatorViews];
  63. if (_indicatorViews.count > 0) {
  64. [self setNeedsLayout];
  65. }
  66. }
  67. - (void)setCurrentPage:(NSInteger)currentPage {
  68. if (_currentPage == currentPage || _indicatorViews.count <= currentPage) {
  69. return;
  70. }
  71. _currentPage = currentPage;
  72. if (!CGSizeEqualToSize(_currentPageIndicatorSize, _pageIndicatorSize)) {
  73. [self setNeedsLayout];
  74. }
  75. [self updateIndicatorViewsBehavior];
  76. if (self.userInteractionEnabled) {
  77. [self sendActionsForControlEvents:UIControlEventValueChanged];
  78. }
  79. }
  80. - (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate {
  81. if (animate) {
  82. [UIView animateWithDuration:_animateDuring animations:^{
  83. [self setCurrentPage:currentPage];
  84. }];
  85. }else {
  86. [self setCurrentPage:currentPage];
  87. }
  88. }
  89. - (void)setPageIndicatorImage:(UIImage *)pageIndicatorImage {
  90. _pageIndicatorImage = pageIndicatorImage;
  91. [self updateIndicatorViewsBehavior];
  92. }
  93. - (void)setCurrentPageIndicatorImage:(UIImage *)currentPageIndicatorImage {
  94. _currentPageIndicatorImage = currentPageIndicatorImage;
  95. [self updateIndicatorViewsBehavior];
  96. }
  97. - (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor {
  98. _pageIndicatorTintColor = pageIndicatorTintColor;
  99. [self updateIndicatorViewsBehavior];
  100. }
  101. - (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor {
  102. _currentPageIndicatorTintColor = currentPageIndicatorTintColor;
  103. [self updateIndicatorViewsBehavior];
  104. }
  105. - (void)setPageIndicatorSize:(CGSize)pageIndicatorSize {
  106. if (CGSizeEqualToSize(_pageIndicatorSize, pageIndicatorSize)) {
  107. return;
  108. }
  109. _pageIndicatorSize = pageIndicatorSize;
  110. if (CGSizeEqualToSize(_currentPageIndicatorSize, CGSizeZero) || (_currentPageIndicatorSize.width < pageIndicatorSize.width && _currentPageIndicatorSize.height < pageIndicatorSize.height)) {
  111. _currentPageIndicatorSize = pageIndicatorSize;
  112. }
  113. if (_indicatorViews.count > 0) {
  114. [self setNeedsLayout];
  115. }
  116. }
  117. - (void)setPageIndicatorSpaing:(CGFloat)pageIndicatorSpaing {
  118. _pageIndicatorSpaing = pageIndicatorSpaing;
  119. if (_indicatorViews.count > 0) {
  120. [self setNeedsLayout];
  121. }
  122. }
  123. - (void)setCurrentPageIndicatorSize:(CGSize)currentPageIndicatorSize {
  124. if (CGSizeEqualToSize(_currentPageIndicatorSize, currentPageIndicatorSize)) {
  125. return;
  126. }
  127. _currentPageIndicatorSize = currentPageIndicatorSize;
  128. if (_indicatorViews.count > 0) {
  129. [self setNeedsLayout];
  130. }
  131. }
  132. - (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
  133. [super setContentHorizontalAlignment:contentHorizontalAlignment];
  134. if (_indicatorViews.count > 0) {
  135. [self setNeedsLayout];
  136. }
  137. }
  138. - (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
  139. [super setContentVerticalAlignment:contentVerticalAlignment];
  140. if (_indicatorViews.count > 0) {
  141. [self setNeedsLayout];
  142. }
  143. }
  144. #pragma mark - update indicator
  145. - (void)updateIndicatorViews {
  146. if (!self.superview && !_forceUpdate) {
  147. return;
  148. }
  149. if (_indicatorViews.count == _numberOfPages) {
  150. [self updateIndicatorViewsBehavior];
  151. return;
  152. }
  153. NSMutableArray *indicatorViews = _indicatorViews ? [_indicatorViews mutableCopy] :[NSMutableArray array];
  154. if (indicatorViews.count < _numberOfPages) {
  155. for (NSInteger idx = indicatorViews.count; idx < _numberOfPages; ++idx) {
  156. UIImageView *indicatorView = [[UIImageView alloc]init];
  157. indicatorView.contentMode = _indicatorImageContentMode;
  158. [self addSubview:indicatorView];
  159. [indicatorViews addObject:indicatorView];
  160. }
  161. }else if (indicatorViews.count > _numberOfPages) {
  162. for (NSInteger idx = indicatorViews.count - 1; idx >= _numberOfPages; --idx) {
  163. UIImageView *indicatorView = indicatorViews[idx];
  164. [indicatorView removeFromSuperview];
  165. [indicatorViews removeObjectAtIndex:idx];
  166. }
  167. }
  168. _indicatorViews = [indicatorViews copy];
  169. [self updateIndicatorViewsBehavior];
  170. }
  171. - (void)updateIndicatorViewsBehavior {
  172. if (_indicatorViews.count == 0 || (!self.superview && !_forceUpdate)) {
  173. return;
  174. }
  175. if (_hidesForSinglePage && _indicatorViews.count == 1) {
  176. UIImageView *indicatorView = _indicatorViews.lastObject;
  177. indicatorView.hidden = YES;
  178. return;
  179. }
  180. NSInteger index = 0;
  181. for (UIImageView *indicatorView in _indicatorViews) {
  182. if (_pageIndicatorImage) {
  183. indicatorView.contentMode = _indicatorImageContentMode;
  184. indicatorView.image = _currentPage == index ? _currentPageIndicatorImage : _pageIndicatorImage;
  185. }else {
  186. indicatorView.image = nil;
  187. indicatorView.backgroundColor = _currentPage == index ? _currentPageIndicatorTintColor : _pageIndicatorTintColor;
  188. }
  189. indicatorView.hidden = NO;
  190. ++index;
  191. }
  192. }
  193. #pragma mark - layout
  194. - (void)layoutIndicatorViews {
  195. if (_indicatorViews.count == 0) {
  196. return;
  197. }
  198. CGFloat orignX = 0;
  199. CGFloat centerY = 0;
  200. CGFloat pageIndicatorSpaing = _pageIndicatorSpaing;
  201. switch (self.contentHorizontalAlignment) {
  202. case UIControlContentHorizontalAlignmentCenter:
  203. // ignore contentInset
  204. orignX = (CGRectGetWidth(self.frame) - (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) - _currentPageIndicatorSize.width)/2;
  205. break;
  206. case UIControlContentHorizontalAlignmentLeft:
  207. orignX = _contentInset.left;
  208. break;
  209. case UIControlContentHorizontalAlignmentRight:
  210. orignX = CGRectGetWidth(self.frame) - ((_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _currentPageIndicatorSize.width) - _contentInset.right;
  211. break;
  212. case UIControlContentHorizontalAlignmentFill:
  213. orignX = _contentInset.left;
  214. if (_indicatorViews.count > 1) {
  215. pageIndicatorSpaing = (CGRectGetWidth(self.frame) - _contentInset.left - _contentInset.right - _pageIndicatorSize.width - (_indicatorViews.count - 1) * _pageIndicatorSize.width)/(_indicatorViews.count - 1);
  216. }
  217. break;
  218. default:
  219. break;
  220. }
  221. switch (self.contentVerticalAlignment) {
  222. case UIControlContentVerticalAlignmentCenter:
  223. centerY = CGRectGetHeight(self.frame)/2;
  224. break;
  225. case UIControlContentVerticalAlignmentTop:
  226. centerY = _contentInset.top + _currentPageIndicatorSize.height/2;
  227. break;
  228. case UIControlContentVerticalAlignmentBottom:
  229. centerY = CGRectGetHeight(self.frame) - _currentPageIndicatorSize.height/2 - _contentInset.bottom;
  230. break;
  231. case UIControlContentVerticalAlignmentFill:
  232. centerY = (CGRectGetHeight(self.frame) - _contentInset.top - _contentInset.bottom)/2 + _contentInset.top;
  233. break;
  234. default:
  235. break;
  236. }
  237. NSInteger index = 0;
  238. for (UIImageView *indicatorView in _indicatorViews) {
  239. if (_pageIndicatorImage) {
  240. indicatorView.layer.cornerRadius = 0;
  241. }else {
  242. indicatorView.layer.cornerRadius = _currentPage == index ? _currentPageIndicatorSize.height/2 : _pageIndicatorSize.height/2;
  243. }
  244. CGSize size = index == _currentPage ? _currentPageIndicatorSize : _pageIndicatorSize;
  245. indicatorView.frame = CGRectMake(orignX, centerY - size.height/2, size.width, size.height);
  246. orignX += size.width + pageIndicatorSpaing;
  247. ++index;
  248. }
  249. }
  250. - (void)layoutSubviews {
  251. [super layoutSubviews];
  252. [self layoutIndicatorViews];
  253. }
  254. @end