系统自带的分段选择就是 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 = ;
const static CGFloat _margin_right = ;
const static CGFloat _margin_top = ;
const static CGFloat _margin_bottom = ;
const static CGFloat _margin_space = ; 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 = ;
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], )];
} - (void)updateSelectSeg{
[self storeSegmentedWidth];
[self reloadData];
[UIView animateWithDuration:0.3 animations:^{
CGRect lineRext = [self measureLineFrame];
self.lineView.frame = lineRext;
}]; [self setContentOffset:CGPointMake([self measureContentOffsetX], ) animated:YES];
}
#pragma mark ========== 储存计算好的item宽度 ==========
///每次切换时更新
- (void)storeSegmentedWidth{
_selectIndex = ;
_totalContentWidth = ;
[self.widthsArray removeAllObjects]; if (_selectString) {
for (int i = ; i < _titleArray.count; i ++) {
NSString *title = _titleArray[i];
if ([title isEqualToString:_selectString]) {
_selectIndex = i;
break;
}
}
} for (int i = ; 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 - ) {
_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 = ;
for (int i = ; 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)/ : (_line_width - widthSelect)/;
lineRectX = lineRectX + _margin_left + lastLocation; lineRect = CGRectMake(lineRectX, self.bounds.size.height - _line_height - , _line_width, _line_height);
return lineRect;
}
#pragma mark ========== 计算偏移量 ==========
- (CGFloat)measureContentOffsetX{
CGFloat selfWidth = self.bounds.size.width; ///先计算点击的item中心点
CGFloat selectedCenterX = ;
for (int i = ; i < _selectIndex; i ++) {
NSNumber *number = self.widthsArray[i];
selectedCenterX = selectedCenterX + [number floatValue] + _margin_space;
}
CGFloat widthSelect = [self.widthsArray[_selectIndex] floatValue];
selectedCenterX = selectedCenterX + widthSelect/; if (_totalContentWidth <= selfWidth) {///充满内部不做偏移
return ;
} if (selectedCenterX <= selfWidth/) {
return ;
}
else if (selectedCenterX >= _totalContentWidth - selfWidth/){
return _totalContentWidth - selfWidth;
}
else{
return selectedCenterX - selfWidth/;
}
}
#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],);
}
- (__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/;
}
return _lineView;
} @end

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

  1. iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码

    iOS精选源码 APP启动视频 自定义按钮,图片可调整图文间距SPButton 一款定制性极高的轮播图,可自定义轮播图Item的样式(或只... iOS 筛选菜单 分段选择器 仿微信导航栏的实现,让你 ...

  2. iOS分段选择器、旅行App、标度尺、对对碰小游戏、自定义相册等源码

    iOS精选源码 企业级开源项目,模仿艺龙旅行App 标签选择器--LeeTagView CSSegmentedControl常用的分段选择器,简单易用! 仿微信左滑删除 IOS左滑返回 输入框 iOS ...

  3. UISegmentedControl字体大小,颜色,选中颜色,左边椭圆,右边直线的Button 解决之iOS开发之分段控制器UISegmentedControl

        NSArray *segmentedArray = [NSArrayarrayWithObjects:STR(@"Mynews"),STR(@"Systemmes ...

  4. iOS 如何自定义UISearchBar 中textField的高度

    iOS 如何自定义UISearchBar 中textField的高度 只需设置下边的方法就可以 [_searchBar setSearchFieldBackgroundImage:[UIImage i ...

  5. iOS 隐藏自定义tabbar

    iOS  隐藏自定义tabbar -(void)viewWillAppear:(BOOL)animated { NSArray *array=self.tabBarController.view.su ...

  6. ios 实现自定义状态栏StatusBar 和 导航栏navigationBar 的状态和颜色

    很多app中可以看到不同与导航栏的状态栏的颜色,他妈的真绕嘴. 一.更改状态栏颜色 (StatusBar) 就是比如导航栏是红色的状态栏是绿色的. 要实现这样的效果其实很简单,就是添加一个背景view ...

  7. iOS开发之分段控制器(UISegmentedControl)

    今天我们来说下iOS中的分段选择控制器UISegmentedControl,这一控件有什么作用呢 每个segment都能被点击,相当于集成了多个button 通常我们会点击不同的segment来切换不 ...

  8. 自定义 Button 选择器

    极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以 ...

  9. picker-view、微信小程序自定义时间选择器(非官方)

    picker-view自定义时间选择器 官网的自定义时间选择器比较简陋.日期不准 下面是我自己写的一个demo <view class="baseList"> < ...

随机推荐

  1. JSP + Session Cookie详解

    篇幅较大,对JSP进行了非常详细的讲解,并解释了Session和Cookie的实现原理 ,预计看完需要20分钟左右,慢慢享受吧 JSP概述 掌握了servlet后,就可以利用servlet来开发动态页 ...

  2. hibernate绑定session

    session session是一种单实例对象 简单说就是自己用 别人不能用.在一些项目中很多人一起来操作 所以我们可以把session与我们的本地线程一起绑定,本地线程的特点就是执行一次 从创建到销 ...

  3. iOS开发UI篇—Quartz2D使用(图形上下文栈

    转自:http://www.cnblogs.com/wendingding/p/3782489.html 一.qurza2d是怎么将绘图信息和绘图的属性绘制到图形上下文中去的? 说明: 新建一个项目, ...

  4. Zookeeper选取机制

    1)半数机制:集群中半数以上机器存活,集群可用.所以Zookeeper适合安装奇数台服务器. 2)Zookeeper虽然在配置文件中并没有指定Master和Slave.但是,Zookeeper工作时, ...

  5. linux 安装jmeter

    一 下载jdk sudo apt install oracle-java8-installer 二 网站下载 jmeter 三 对jmeter文件夹 赋权 我都是777 chmod -R 777 ap ...

  6. jquery (对内容,元素,属性,class的操作)

    对内容的操作: 捕获:获得内容 text() - 设置或返回所选元素的文本内容html() - 设置或返回所选元素的内容(包括 HTML 标记)val() - 设置或返回表单字段的值. 设置:设置内容 ...

  7. JS-常见数据结构

    常见数据结构 这一章节我们将来学习数据结构的内容.经常会有人提问说:学习数据结构或者算法对于前端工程师有用么? 总的来说,这些基础学科在短期内收效确实甚微,但是我们首先不要将自己局限在前端工程师这点上 ...

  8. Vue ---- 项目与环境搭建 初始项目结构 Vue生命周期

    目录 1. vue环境搭建 2. Vue项目搭建 pycharm配置并启动vue项目 3 . 认识项目 1. vue项目目录结构 2. 配置文件:vue.config.js 3. main.js 4. ...

  9. poj 2398 Toy Storage(计算几何)

    题目传送门:poj 2398 Toy Storage 题目大意:一个长方形的箱子,里面有一些隔板,每一个隔板都可以纵切这个箱子.隔板将这个箱子分成了一些隔间.向其中扔一些玩具,每个玩具有一个坐标,求有 ...

  10. HttpRunner学习11--指定用例运行次数

    前言 在HttpRunner中,一般情况下,我们写的用例脚本都是每次运行一次,如果我们想要指定用例运行的次数,可以通过 times 关键字来实现. 测试场景 在这里,我们以访问 TesterHome ...