当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS-关于自定义分段选择器的一些小事(Segmented)

iOS-关于自定义分段选择器的一些小事(Segmented)

2019年07月09日  | 移动技术网移动技术  | 我要评论

系统自带的分段选择就是 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

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网