iOS-关于自定义分段选择器的一些小事(Segmented)
程序员文章站
2022-03-18 16:45:11
系统自带的分段选择就是 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
上一篇: 我的Python之路 day1
下一篇: Maven学习