SegmentHeaderView.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. //
  2. // SegmentHeaderView.m
  3. // PersonalCenter
  4. //
  5. // Created by Arch on 2018/8/20.
  6. // Copyright © 2018年 mint_bin. All rights reserved.
  7. //
  8. #import "SegmentHeaderView.h"
  9. //#define kWidth self.frame.size.width
  10. #define NORMAL_FONT [UIFont systemFontOfSize:15]
  11. @interface SegmentHeaderViewCollectionViewCell ()
  12. @property (nonatomic, strong) UILabel *titleLabel;
  13. @end;
  14. @implementation SegmentHeaderViewCollectionViewCell
  15. - (instancetype)initWithFrame:(CGRect)frame {
  16. self = [super initWithFrame:frame];
  17. if (self) {
  18. self.frame = frame;
  19. [self.contentView addSubview:self.titleLabel];
  20. [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  21. make.edges.mas_equalTo(0);
  22. }];
  23. }
  24. return self;
  25. }
  26. - (UILabel *)titleLabel {
  27. if (!_titleLabel) {
  28. _titleLabel = [[UILabel alloc] init];
  29. _titleLabel.textAlignment = NSTextAlignmentCenter;
  30. _titleLabel.font = NORMAL_FONT;
  31. _titleLabel.textColor = UIColorHex(0x666666);
  32. }
  33. return _titleLabel;
  34. }
  35. @end
  36. @interface SegmentHeaderView () <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
  37. @property (nonatomic, strong) UICollectionView *collectionView;
  38. @property (nonatomic, copy) NSArray *titleArray;
  39. @property (nonatomic, strong) UIView *moveLine;
  40. @property (nonatomic, strong) UIView *separator;
  41. @property (nonatomic, assign) BOOL selectedCellExist;
  42. @end
  43. CGFloat const SegmentHeaderViewHeight = 37;
  44. static NSString * const SegmentHeaderViewCollectionViewCellIdentifier = @"SegmentHeaderViewCollectionViewCell";
  45. static CGFloat const MoveLineHeight = 2;
  46. static CGFloat const SeparatorHeight = 0.5;
  47. static CGFloat const CellSpacing = 15;
  48. static CGFloat const CollectionViewHeight = SegmentHeaderViewHeight - SeparatorHeight;
  49. @implementation SegmentHeaderView
  50. #pragma mark - Life
  51. - (instancetype)initWithFrame:(CGRect)frame titleArray:(NSArray *)titleArray {
  52. if (self = [super initWithFrame:frame]) {
  53. [self setupSubViews];
  54. self.titleArray = titleArray;
  55. self.selectedIndex = 0;
  56. }
  57. return self;
  58. }
  59. #pragma mark - Public Method
  60. - (void)changeItemWithTargetIndex:(NSUInteger)targetIndex {
  61. if (_selectedIndex == targetIndex) {
  62. return;
  63. }
  64. SegmentHeaderViewCollectionViewCell *selectedCell = [self getCell:_selectedIndex];
  65. if (selectedCell) {
  66. selectedCell.titleLabel.textColor = UIColorHex(0x666666);
  67. }
  68. SegmentHeaderViewCollectionViewCell *targetCell = [self getCell:targetIndex];
  69. if (targetCell) {
  70. targetCell.titleLabel.textColor = UIColorHex(0x3979D3);
  71. }
  72. _selectedIndex = targetIndex;
  73. [self layoutAndScrollToSelectedItem];
  74. }
  75. #pragma mark - Private Method
  76. - (void)setupSubViews {
  77. [self addSubview:self.collectionView];
  78. [self.collectionView addSubview:self.moveLine];
  79. [self addSubview:self.separator];
  80. [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
  81. make.top.left.right.mas_equalTo(0);
  82. make.height.mas_equalTo(CollectionViewHeight);
  83. }];
  84. [self.moveLine mas_makeConstraints:^(MASConstraintMaker *make) {
  85. make.top.mas_equalTo(CollectionViewHeight - MoveLineHeight);
  86. make.height.mas_equalTo(MoveLineHeight);
  87. }];
  88. [self.separator mas_makeConstraints:^(MASConstraintMaker *make) {
  89. make.top.equalTo(self.collectionView.mas_bottom);
  90. make.left.right.mas_equalTo(0);
  91. make.height.mas_equalTo(SeparatorHeight);
  92. }];
  93. }
  94. - (SegmentHeaderViewCollectionViewCell *)getCell:(NSUInteger)Index {
  95. return (SegmentHeaderViewCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:Index inSection:0]];
  96. }
  97. - (void)layoutAndScrollToSelectedItem {
  98. [self.collectionView.collectionViewLayout invalidateLayout];
  99. [self.collectionView setNeedsLayout];
  100. [self.collectionView layoutIfNeeded];
  101. [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:_selectedIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
  102. if (self.selectedItemHelper) {
  103. self.selectedItemHelper(_selectedIndex);
  104. }
  105. SegmentHeaderViewCollectionViewCell *selectedCell = [self getCell:_selectedIndex];
  106. if (selectedCell) {
  107. self.selectedCellExist = YES;
  108. [self updateMoveLineLocation];
  109. } else {
  110. self.selectedCellExist = NO;
  111. //这种情况下updateMoveLineLocation将在self.collectionView滚动结束后执行(代理方法scrollViewDidEndScrollingAnimation)
  112. }
  113. }
  114. - (void)setupMoveLineDefaultLocation {
  115. CGFloat firstCellWidth = [self getWidthWithContent:self.titleArray[0]];
  116. [self.moveLine mas_updateConstraints:^(MASConstraintMaker *make) {
  117. make.width.mas_equalTo(firstCellWidth);
  118. make.left.mas_equalTo(CellSpacing);
  119. }];
  120. }
  121. - (void)updateMoveLineLocation {
  122. SegmentHeaderViewCollectionViewCell *cell = [self getCell:_selectedIndex];
  123. [UIView animateWithDuration:0.25 animations:^{
  124. [self.moveLine mas_remakeConstraints:^(MASConstraintMaker *make) {
  125. make.top.mas_equalTo(CollectionViewHeight - MoveLineHeight);
  126. make.height.mas_equalTo(MoveLineHeight);
  127. make.width.centerX.equalTo(cell.titleLabel);
  128. }];
  129. [self.collectionView setNeedsLayout];
  130. [self.collectionView layoutIfNeeded];
  131. }];
  132. }
  133. - (CGFloat)getWidthWithContent:(NSString *)content {
  134. CGRect rect = [content boundingRectWithSize:CGSizeMake(MAXFLOAT, CollectionViewHeight)
  135. options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
  136. attributes:@{NSFontAttributeName:NORMAL_FONT}
  137. context:nil
  138. ];
  139. return ceilf(rect.size.width);;
  140. }
  141. #pragma mark - UICollectionViewDelegateFlowLayout
  142. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
  143. CGFloat itemWidth = [self getWidthWithContent:self.titleArray[indexPath.row]];
  144. return CGSizeMake(itemWidth, SegmentHeaderViewHeight - 1);
  145. }
  146. #pragma mark - UICollectionViewDataSource
  147. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  148. return self.titleArray.count;
  149. }
  150. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  151. SegmentHeaderViewCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:SegmentHeaderViewCollectionViewCellIdentifier forIndexPath:indexPath];
  152. cell.titleLabel.text = self.titleArray[indexPath.row];
  153. cell.titleLabel.textColor = _selectedIndex == indexPath.row ? UIColorHex(0x3979D3) : UIColorHex(0x666666);
  154. return cell;
  155. }
  156. #pragma mark - UICollectionViewDelegate
  157. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  158. [collectionView deselectItemAtIndexPath:indexPath animated:YES];
  159. [self changeItemWithTargetIndex:indexPath.row];
  160. }
  161. - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
  162. if (!self.selectedCellExist) {
  163. [self updateMoveLineLocation];
  164. }
  165. }
  166. #pragma mark - Setter
  167. - (void)setTitleArray:(NSArray *)titleArray {
  168. _titleArray = titleArray.copy;
  169. [self.collectionView reloadData];
  170. }
  171. - (void)setSelectedIndex:(NSUInteger)selectedIndex {
  172. if (self.titleArray == nil && self.titleArray.count == 0) {
  173. return;
  174. }
  175. if (selectedIndex >= self.titleArray.count) {
  176. _selectedIndex = self.titleArray.count - 1;
  177. } else {
  178. _selectedIndex = selectedIndex;
  179. }
  180. //设置初始选中位置
  181. if (_selectedIndex == 0) {
  182. [self setupMoveLineDefaultLocation];
  183. } else {
  184. [self layoutAndScrollToSelectedItem];
  185. }
  186. }
  187. #pragma mark - Getter
  188. - (UICollectionView *)collectionView {
  189. if (!_collectionView) {
  190. UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
  191. flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  192. flowLayout.minimumLineSpacing = 0;
  193. flowLayout.minimumInteritemSpacing = CellSpacing;
  194. flowLayout.sectionInset = UIEdgeInsetsMake(0, CellSpacing, 0, CellSpacing);
  195. _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, kWidth, CollectionViewHeight) collectionViewLayout:flowLayout];
  196. _collectionView.showsHorizontalScrollIndicator = NO;
  197. _collectionView.backgroundColor = [UIColor whiteColor];
  198. _collectionView.delegate = self;
  199. _collectionView.dataSource = self;
  200. _collectionView.bounces = NO;
  201. [_collectionView registerClass:[SegmentHeaderViewCollectionViewCell class] forCellWithReuseIdentifier:SegmentHeaderViewCollectionViewCellIdentifier];
  202. }
  203. return _collectionView;
  204. }
  205. - (UIView *)moveLine {
  206. if (!_moveLine) {
  207. _moveLine = [[UIView alloc] init];
  208. _moveLine.backgroundColor = UIColorHex(0x3979D3);
  209. }
  210. return _moveLine;
  211. }
  212. - (UIView *)separator {
  213. if (!_separator) {
  214. _separator = [[UIView alloc] init];
  215. _separator.backgroundColor = [UIColor lightGrayColor];
  216. }
  217. return _separator;
  218. }
  219. @end