系統自帶的分段選擇就是 UISegmentedControl ,也有一些大佬自定義的 Segmented ,比如Git上的 HMSegmentedControl ,我以前最初的項目中,也有用到過,如果自己寫,或者想自定義一些UI,該從哪裡出發,其實在用過 HMSegmentedControl 之後, ...
系統自帶的分段選擇就是 UISegmentedControl ,也有一些大佬自定義的 Segmented ,比如Git上的 HMSegmentedControl ,我以前最初的項目中,也有用到過,如果自己寫,或者想自定義一些UI,該從哪裡出發,其實在用過 HMSegmentedControl 之後,大致就有思路了,如果想簡單的實現下,可以利用 UICollectionView 來實現,下麵是我利用 UICollectionView 寫的一個簡單的小慄子,效果圖
設計思路
首先利用 UICollectionView 處理每個item的大小,確切的說是寬度,那麼就要每次選中一個item後,重新計算所有的item的寬度,同時計算 UICollectionView 的 contentSize.width;
計算每個item寬度分為兩種情況,一種是選中的字體的顯示,一種是未選中的字體顯示,比如字體大小,顏色等,然後根據字體大小字元串長度,計算出字體需要展示的寬度,並計算對應的item寬度,最後把每個item的寬度保存起來,用於在 UICollectionView 代理方法中做處理;
計算 contentSize.width 由上圖可知,是由兩邊的間距,item之間的間距和每個item的總和,目的是利用 contentSize.width 計算下劃線的位置;
具體實現
#import "XKCollectionView.h" ///四周邊距 const static CGFloat _margin_left = 5; const static CGFloat _margin_right = 5; const static CGFloat _margin_top = 0; const static CGFloat _margin_bottom = 2; const static CGFloat _margin_space = 15; const static CGFloat _line_width = 30.0; const static CGFloat _line_height = 3.0; @interface XKCollectionView ()<UICollectionViewDataSource,UICollectionViewDelegateFlowLayout> ///臨時數據 @property (nonatomic,strong) NSArray<NSString *> *titleArray; ///每個item的寬度 @property (nonatomic,strong) NSMutableArray *widthsArray; ///底部線條 @property (nonatomic,strong) UIView *lineView; ///選中的item索引 @property (nonatomic,assign) NSInteger selectIndex; ///選中的item string @property (nonatomic,strong) NSString *selectString; ////計算出來的總寬度,用於設置 UICollectionView.contentSize.width @property (nonatomic,assign) CGFloat totalContentWidth; @end @implementation XKCollectionView - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout{ self = [super initWithFrame:frame collectionViewLayout:layout]; if (self) { [self setup]; } return self; } - (void)setup{ _selectIndex = 0; self.widthsArray = [NSMutableArray array]; [self addSubview:self.lineView]; self.backgroundColor = [UIColor whiteColor]; self.showsHorizontalScrollIndicator = NO; self.delegate = self; self.dataSource = self; [self registerClass:[XKCollectionViewCell class] forCellWithReuseIdentifier:@"XKCollectionViewCell"]; _titleArray = @[@"一級建造師",@"二級建造師",@"造價工程師",@"咨詢工程師",@"註冊安全工程師",@"監理工程師",@"註冊電氣工程師",@"環境影響評價工程師",@"註冊城鄉規劃師",@"註冊消防工程師"]; [self storeSegmentedWidth]; [self reloadData]; CGRect lineRext = [self measureLineFrame]; self.lineView.frame = lineRext; ///設置偏移量 [self setContentOffset:CGPointMake([self measureContentOffsetX], 0)]; } - (void)updateSelectSeg{ [self storeSegmentedWidth]; [self reloadData]; [UIView animateWithDuration:0.3 animations:^{ CGRect lineRext = [self measureLineFrame]; self.lineView.frame = lineRext; }]; [self setContentOffset:CGPointMake([self measureContentOffsetX], 0) animated:YES]; } #pragma mark ========== 儲存計算好的item寬度 ========== ///每次切換時更新 - (void)storeSegmentedWidth{ _selectIndex = 0; _totalContentWidth = 0; [self.widthsArray removeAllObjects]; if (_selectString) { for (int i = 0; i < _titleArray.count; i ++) { NSString *title = _titleArray[i]; if ([title isEqualToString:_selectString]) { _selectIndex = i; break; } } } for (int i = 0; i < _titleArray.count; i ++) { CGSize size = [self measureTitleIndex:i]; NSNumber *value = [NSNumber numberWithFloat:size.width]; [self.widthsArray addObject:value]; _totalContentWidth = _totalContentWidth + size.width; if (i < _titleArray.count - 1) { _totalContentWidth = _totalContentWidth + _margin_space; } } _totalContentWidth = _totalContentWidth + _margin_left + _margin_right; } - (CGSize)measureTitleIndex:(NSUInteger)index { if (index >= _titleArray.count) { return CGSizeZero; } id title = _titleArray[index]; CGSize size = CGSizeZero; BOOL selected = (index == _selectIndex); NSDictionary *titleAttrs = selected ? [self resultingSelectedTitleTextAttributes] : [self resultingTitleTextAttributes]; size = [(NSString *)title sizeWithAttributes:titleAttrs]; UIFont *font = titleAttrs[@"NSFont"]; size = CGSizeMake(ceil(size.width), ceil(size.height - font.descender)); CGSize resault = CGRectIntegral((CGRect){CGPointZero, size}).size; return resault; } - (NSDictionary *)resultingSelectedTitleTextAttributes { NSDictionary *resultingAttrs = @{NSForegroundColorAttributeName : [UIColor blackColor] ,NSFontAttributeName:[UIFont fontWithName:@"Helvetica-Bold" size:18.0]}; return resultingAttrs; } - (NSDictionary *)resultingTitleTextAttributes { NSDictionary *resultingAttrs = @{NSForegroundColorAttributeName : [UIColor lightGrayColor],NSFontAttributeName:[UIFont systemFontOfSize:14.0]}; return resultingAttrs; } #pragma mark ========== 計算下劃線位置 ========== - (CGRect)measureLineFrame{ CGRect lineRect = CGRectZero; CGFloat lineRectX = 0; for (int i = 0; i < _selectIndex; i ++) { NSNumber *number = self.widthsArray[i]; lineRectX = lineRectX + [number floatValue] + _margin_space; } CGFloat widthSelect = [self.widthsArray[_selectIndex] floatValue]; CGFloat lastLocation = widthSelect >= _line_width ? (widthSelect - _line_width)/2 : (_line_width - widthSelect)/2; lineRectX = lineRectX + _margin_left + lastLocation; lineRect = CGRectMake(lineRectX, self.bounds.size.height - _line_height - 2, _line_width, _line_height); return lineRect; } #pragma mark ========== 計算偏移量 ========== - (CGFloat)measureContentOffsetX{ CGFloat selfWidth = self.bounds.size.width; ///先計算點擊的item中心點 CGFloat selectedCenterX = 0; for (int i = 0; i < _selectIndex; i ++) { NSNumber *number = self.widthsArray[i]; selectedCenterX = selectedCenterX + [number floatValue] + _margin_space; } CGFloat widthSelect = [self.widthsArray[_selectIndex] floatValue]; selectedCenterX = selectedCenterX + widthSelect/2; if (_totalContentWidth <= selfWidth) {///充滿內部不做偏移 return 0; } if (selectedCenterX <= selfWidth/2) { return 0; } else if (selectedCenterX >= _totalContentWidth - selfWidth/2){ return _totalContentWidth - selfWidth; } else{ return selectedCenterX - selfWidth/2; } } #pragma mark ========== 代理 ========== - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return _titleArray.count; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{ return _margin_space; } - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{ return UIEdgeInsetsMake(_margin_top, _margin_left, _margin_bottom, _margin_right); } //item大小 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ NSNumber *number = self.widthsArray[indexPath.row]; return CGSizeMake([number floatValue],30); } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ XKCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"XKCollectionViewCell" forIndexPath:indexPath]; NSString *title = _titleArray[indexPath.row]; cell.title = title; if (indexPath.row == _selectIndex) { cell.isSelectd = YES; } else{ cell.isSelectd = NO; } return cell; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ _selectString = _titleArray[indexPath.row]; [self updateSelectSeg]; } #pragma mark ========== 變數 ========== - (UIView *)lineView{ if(!_lineView){ _lineView = [[UIView alloc]init]; _lineView.backgroundColor = [UIColor purpleColor]; _lineView.layer.masksToBounds = YES; _lineView.layer.cornerRadius = _line_height/2; } return _lineView; } @end