XLsn0wScrollUnderlineButton.m 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #import "XLsn0wScrollUnderlineButton.h"
  2. static NSString *const cellIdentifier = @"XLsn0wScrollUnderlineButtonCell";
  3. @interface XLsn0wScrollUnderlineButton () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
  4. @property (nonatomic, strong) UICollectionView *collectionView;
  5. @property (nonatomic, strong) UICollectionViewFlowLayout *layout;
  6. @end
  7. @implementation XLsn0wScrollUnderlineButton
  8. - (instancetype)initWithFrame:(CGRect)frame {
  9. if (self = [super initWithFrame:frame]) {
  10. self.backgroundColor = [UIColor whiteColor];
  11. //设置颜色默认值
  12. _normalFont = _selectedFont = [UIFont systemFontOfSize:14];
  13. _normalColor = [UIColor blackColor];
  14. _selectedColor = [UIColor blueColor];
  15. _currentIndex = 0;
  16. _lineEdgeInsets = UIEdgeInsetsMake(0, 3, 2, 3);
  17. _cursorEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
  18. }
  19. return self;
  20. }
  21. -(UIView*)lineView
  22. {
  23. if (!_lineView) {
  24. _lineView = [[UIView alloc]init];
  25. _lineView.backgroundColor = [UIColor purpleColor];
  26. [self.collectionView addSubview:_lineView];
  27. }
  28. return _lineView;
  29. }
  30. -(UICollectionView*)collectionView {
  31. if (!_collectionView) {
  32. _layout = [[UICollectionViewFlowLayout alloc]init];
  33. _layout.minimumLineSpacing = 0;
  34. _layout.minimumInteritemSpacing = 0;
  35. _layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  36. CGRect rect = CGRectMake(_cursorEdgeInsets.left, _cursorEdgeInsets.top, CGRectGetWidth(self.bounds)-_cursorEdgeInsets.left-_cursorEdgeInsets.right, CGRectGetHeight(self.bounds)-_cursorEdgeInsets.top-_cursorEdgeInsets.bottom);
  37. _collectionView = [[UICollectionView alloc]initWithFrame:rect collectionViewLayout:_layout];
  38. _collectionView.showsVerticalScrollIndicator = NO;
  39. _collectionView.showsHorizontalScrollIndicator = NO;
  40. _collectionView.scrollsToTop = NO;
  41. _collectionView.backgroundColor = [UIColor whiteColor];
  42. _collectionView.delegate = self;
  43. _collectionView.dataSource = self;
  44. [_collectionView registerClass:[XLsn0wScrollUnderlineButtonCell class] forCellWithReuseIdentifier:cellIdentifier];
  45. [self addSubview:_collectionView];
  46. }
  47. return _collectionView;
  48. }
  49. - (void)reloadData {
  50. [self.collectionView reloadData];
  51. }
  52. -(void)setTitles:(NSArray *)titles {
  53. _titles = titles;
  54. [self reloadData];
  55. }
  56. - (void)setCurrentIndex:(NSInteger)currentIndex {
  57. _currentIndex = currentIndex;
  58. }
  59. /**
  60. * 设置collectionView的偏移量,使得选中的项目居中
  61. *
  62. * @param frame cellFrame
  63. */
  64. -(void)setContentOffsetWithCellFrame:(CGRect)frame
  65. {
  66. CGFloat width = CGRectGetWidth(self.collectionView.frame)/2;
  67. CGFloat offsetX = 0;
  68. if (CGRectGetMidX(frame) <= width) {
  69. offsetX = 0;
  70. }else if (CGRectGetMidX(frame) + width >= self.collectionView.contentSize.width) {
  71. if (CGRectGetMaxX(frame) <= self.collectionView.frame.size.width) {
  72. offsetX = 0;
  73. } else {
  74. offsetX = self.collectionView.contentSize.width - CGRectGetWidth(self.collectionView.frame);
  75. }
  76. }else{
  77. offsetX = CGRectGetMidX(frame)-CGRectGetWidth(self.collectionView.frame)/2;
  78. }
  79. [self.collectionView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
  80. }
  81. /**
  82. * 设置标识线的frame
  83. *
  84. * @param frame cellFrame
  85. */
  86. -(void)resizeLineViewWihtCellFrame:(CGRect)frame animated:(BOOL)animated
  87. {
  88. CGFloat height = 3.0f;
  89. CGRect rect = CGRectMake(CGRectGetMinX(frame)+_lineEdgeInsets.left,
  90. CGRectGetHeight(self.collectionView.frame)-height-_lineEdgeInsets.bottom,
  91. CGRectGetWidth(frame)-_lineEdgeInsets.left*2, height-_lineEdgeInsets.top);
  92. if (animated) {
  93. [UIView animateWithDuration:0.3f animations:^{
  94. self.lineView.frame = rect;
  95. }];
  96. }else{
  97. self.lineView.frame = CGRectMake(0, CGRectGetHeight(self.collectionView.frame)-height-_lineEdgeInsets.bottom, 50, 3);
  98. [self setContentOffsetWithCellFrame:self.lineView.frame];
  99. }
  100. }
  101. /**
  102. * 主动设置cursor选中item
  103. *
  104. * @param index index
  105. */
  106. -(void)selectItemAtIndex:(NSInteger)index
  107. {
  108. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:_currentIndex inSection:0];
  109. [self.collectionView selectItemAtIndexPath:indexPath
  110. animated:YES
  111. scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
  112. [self selectItemAtIndexPath:indexPath];
  113. }
  114. /**
  115. * 设置计算选中的item状态
  116. *
  117. * @param indexPath indexPath
  118. */
  119. -(void)selectItemAtIndexPath:(NSIndexPath*)indexPath {
  120. XLsn0wScrollUnderlineButtonCell *cell = (XLsn0wScrollUnderlineButtonCell*)[self.collectionView cellForItemAtIndexPath:indexPath];
  121. cell.selected = YES;
  122. CGRect rect = cell.frame;
  123. if (!cell) {
  124. UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
  125. rect = attributes.frame;
  126. }
  127. [self setContentOffsetWithCellFrame:rect];
  128. [self resizeLineViewWihtCellFrame:rect animated:YES];
  129. }
  130. /**
  131. * 主动设置使item变为不可选
  132. *
  133. * @param index index
  134. */
  135. -(void)deselectItemAtIndex:(NSInteger)index
  136. {
  137. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
  138. [self.collectionView deselectItemAtIndexPath:indexPath animated:NO];
  139. XLsn0wScrollUnderlineButtonCell *cell = (XLsn0wScrollUnderlineButtonCell*)[self.collectionView cellForItemAtIndexPath:indexPath];
  140. cell.selected = NO;
  141. }
  142. #pragma mark - UICollectionViewDataSource
  143. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  144. return _titles.count;
  145. }
  146. // The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
  147. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  148. {
  149. XLsn0wScrollUnderlineButtonCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
  150. NSString *title = _titles[indexPath.item];
  151. cell.title = title;
  152. cell.normalFont = self.normalFont;
  153. cell.selectedFont = self.selectedFont;
  154. cell.normalColor = self.normalColor;
  155. cell.selectedColor = self.selectedColor;
  156. cell.selected = (indexPath.item == _currentIndex);
  157. if (collectionView.indexPathsForSelectedItems.count <= 0) {
  158. [self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:_currentIndex inSection:0]
  159. animated:NO
  160. scrollPosition:UICollectionViewScrollPositionNone];
  161. [self resizeLineViewWihtCellFrame:cell.frame animated:NO];
  162. }
  163. return cell;
  164. }
  165. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  166. if (_currentIndex == indexPath.item) {
  167. return;
  168. }
  169. _currentIndex = indexPath.item;
  170. self.scrollUnderlineButtonBlock(indexPath.item);
  171. [self selectItemAtIndexPath:indexPath];
  172. }
  173. - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
  174. XLsn0wScrollUnderlineButtonCell *cell = (XLsn0wScrollUnderlineButtonCell*)[collectionView cellForItemAtIndexPath:indexPath];
  175. cell.selected = NO;
  176. }
  177. #pragma mark - UICollectionViewDelegateFlowLayout
  178. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
  179. {
  180. NSString *title = _titles[indexPath.item];
  181. CGSize size = [title sizeWithAttributes:@{NSFontAttributeName:self.selectedFont}];
  182. size = CGSizeMake(size.width+20, CGRectGetHeight(self.bounds));
  183. return size;
  184. }
  185. - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
  186. {
  187. return UIEdgeInsetsMake(0, 0, 0, 0);
  188. }
  189. @end
  190. /****************************XLsn0wScrollUnderlineButtonCell****************************************/
  191. @interface XLsn0wScrollUnderlineButtonCell ()
  192. @property (nonatomic, strong) UILabel *titleLabel;
  193. @end
  194. @implementation XLsn0wScrollUnderlineButtonCell
  195. - (instancetype)initWithFrame:(CGRect)frame {
  196. if (self = [super initWithFrame:frame]) {
  197. self.backgroundColor = [UIColor whiteColor];
  198. _selectedColor = [UIColor blueColor];
  199. _normalColor = [UIColor whiteColor];
  200. _selectedFont = _normalFont = [UIFont systemFontOfSize:14];
  201. _titleLabel = [[UILabel alloc]init];
  202. _titleLabel.textAlignment = NSTextAlignmentCenter;
  203. _titleLabel.backgroundColor = [UIColor clearColor];
  204. [self.contentView addSubview:_titleLabel];
  205. }
  206. return self;
  207. }
  208. -(void)setTitle:(NSString *)title
  209. {
  210. _title = title;
  211. _titleLabel.text = _title;
  212. }
  213. -(void)setSelected:(BOOL)selected
  214. {
  215. super.selected = selected;
  216. if (selected) {
  217. _titleLabel.font = _selectedFont;
  218. _titleLabel.textColor = _selectedColor;
  219. }else{
  220. _titleLabel.font = _normalFont;
  221. _titleLabel.textColor = _normalColor;
  222. }
  223. }
  224. -(void)layoutSubviews
  225. {
  226. [super layoutSubviews];
  227. _titleLabel.frame = self.bounds;
  228. }
  229. @end