先上效果图

设计要求

1、标签的宽度是按内容自适应的

2、一行显示的标签个数是动态的,放得下就放,放不下就换行

3、默认选中第一个

4、至少选中一个标签

实现思路

首先我们从这个效果上来看,这个标签是有选中和不选中状态,那我们首选的控件肯定就是用 UIButton来实现了。

这个小程度的重点就在于标签能自动换行,还是智能的,不是固定一行多少个那种,这个我们通过计算每个按钮实际宽度与屏幕的宽度进行比较就能判断是否需要换行了。

还有一点就是处理 至少选中一个标签的功能,我这里有一种方式,就是控制按钮的 userInteractionEnabled 属性来实现,如果只有一个按钮的时候就把那一个按钮的这个属性给设置成 NO,这样就禁止用户对它进行点击事件了,这个时候其它按钮是可以正常选中的,只要选中的按钮大于1个,那就把刚才那个按钮属性再改成YES,这样那个按钮就又能点了。

具体看代码

创建一个继承于UIView的 XGTagView 类

//
// XGTagView.h
// 动态标签
//
// Created by xgao on 17/3/22.
// Copyright © 2017年 xgao. All rights reserved.
// #import <UIKit/UIKit.h> @interface XGTagView : UIView /**
* 初始化
*
* @param frame frame
* @param tagArray 标签数组
*
* @return
*/
- (instancetype)initWithFrame:(CGRect)frame tagArray:(NSMutableArray*)tagArray; // 标签数组
@property (nonatomic,retain) NSArray* tagArray; // 选中标签文字颜色
@property (nonatomic,retain) UIColor* textColorSelected;
// 默认标签文字颜色
@property (nonatomic,retain) UIColor* textColorNormal; // 选中标签背景颜色
@property (nonatomic,retain) UIColor* backgroundColorSelected;
// 默认标签背景颜色
@property (nonatomic,retain) UIColor* backgroundColorNormal; @end
//
// XGTagView.m
// 动态标签
//
// Created by xgao on 17/3/22.
// Copyright © 2017年 xgao. All rights reserved.
// #import "XGTagView.h" @interface XGTagView() @end @implementation XGTagView /**
* 初始化
*
* @param frame frame
* @param tagArray 标签数组
*
* @return
*/
- (instancetype)initWithFrame:(CGRect)frame tagArray:(NSArray*)tagArray{ self = [super initWithFrame:frame];
if (self) {
_tagArray = tagArray;
[self setUp];
}
return self;
} // 初始化
- (void)setUp{ // 默认颜色
_textColorNormal = [UIColor darkGrayColor];
_textColorSelected = [UIColor whiteColor];
_backgroundColorSelected = [UIColor redColor];
_backgroundColorNormal = [UIColor whiteColor]; // 创建标签按钮
[self createTagButton];
} // 重写set属性
- (void)setTagArray:(NSMutableArray *)tagArray{ _tagArray = tagArray; // 重新创建标签
[self resetTagButton];
} - (void)setTextColorSelected:(UIColor *)textColorSelected{ _textColorSelected = textColorSelected;
// 重新创建标签
[self resetTagButton];
} - (void)setTextColorNormal:(UIColor *)textColorNormal{ _textColorNormal = textColorNormal;
// 重新创建标签
[self resetTagButton];
} - (void)setBackgroundColorSelected:(UIColor *)backgroundColorSelected{ _backgroundColorSelected = backgroundColorSelected;
// 重新创建标签
[self resetTagButton];
} - (void)setBackgroundColorNormal:(UIColor *)backgroundColorNormal{ _backgroundColorNormal = backgroundColorNormal;
// 重新创建标签
[self resetTagButton];
} #pragma mark - Private // 重新创建标签
- (void)resetTagButton{ // 移除之前的标签
for (UIButton* btn in self.subviews) {
[btn removeFromSuperview];
}
// 重新创建标签
[self createTagButton];
} // 创建标签按钮
- (void)createTagButton{ // 按钮高度
CGFloat btnH = ;
// 距离左边距
CGFloat leftX = ;
// 距离上边距
CGFloat topY = ;
// 按钮左右间隙
CGFloat marginX = ;
// 按钮上下间隙
CGFloat marginY = ;
// 文字左右间隙
CGFloat fontMargin = ; for (int i = ; i < _tagArray.count; i++) { UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(marginX + leftX, topY, , btnH);
btn.tag = +i;
// 默认选中第一个
if (i == ) {
btn.selected = YES;
} // 按钮文字
[btn setTitle:_tagArray[i] forState:UIControlStateNormal]; //------ 默认样式
//按钮文字默认样式
NSMutableAttributedString* btnDefaultAttr = [[NSMutableAttributedString alloc]initWithString:btn.titleLabel.text];
// 文字大小
[btnDefaultAttr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:] range:NSMakeRange(, btn.titleLabel.text.length)];
// 默认颜色
[btnDefaultAttr addAttribute:NSForegroundColorAttributeName value:self.textColorNormal range:NSMakeRange(, btn.titleLabel.text.length)];
[btn setAttributedTitle:btnDefaultAttr forState:UIControlStateNormal]; // 默认背景颜色
[btn setBackgroundImage:[self imageWithColor:self.backgroundColorNormal] forState:UIControlStateNormal]; //----- 选中样式
// 选中字体颜色
NSMutableAttributedString* btnSelectedAttr = [[NSMutableAttributedString alloc]initWithString:btn.titleLabel.text];
// 选中颜色
[btnSelectedAttr addAttribute:NSForegroundColorAttributeName value:self.textColorSelected range:NSMakeRange(, btn.titleLabel.text.length)];
// 选中文字大小
[btnSelectedAttr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:] range:NSMakeRange(, btn.titleLabel.text.length)];
[btn setAttributedTitle:btnSelectedAttr forState:UIControlStateSelected]; // 选中背景颜色
[btn setBackgroundImage:[self imageWithColor:self.backgroundColorSelected] forState:UIControlStateSelected]; // 圆角
btn.layer.cornerRadius = btn.frame.size.height / .f;
btn.layer.masksToBounds = YES;
// 边框
btn.layer.borderColor = [UIColor lightGrayColor].CGColor;
btn.layer.borderWidth = 0.5; // 设置按钮的边距、间隙
[self setTagButtonMargin:btn fontMargin:fontMargin]; // 处理换行
if (btn.frame.origin.x + btn.frame.size.width + marginX > self.frame.size.width) {
// 换行
topY += btnH + marginY; // 重置
leftX = ;
btn.frame = CGRectMake(marginX + leftX, topY, , btnH); // 设置按钮的边距、间隙
[self setTagButtonMargin:btn fontMargin:fontMargin];
} // 重置高度
CGRect frame = btn.frame;
frame.size.height = btnH;
btn.frame = frame; //----- 选中事件
[btn addTarget:self action:@selector(selectdButton:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:btn]; leftX += btn.frame.size.width + marginX;
} // 检测按钮状态,最少选中一个
[self checkButtonState];
} // 设置按钮的边距、间隙
- (void)setTagButtonMargin:(UIButton*)btn fontMargin:(CGFloat)fontMargin{ // 按钮自适应
[btn sizeToFit]; // 重新计算按钮文字左右间隙
CGRect frame = btn.frame;
frame.size.width += fontMargin*;
btn.frame = frame;
} // 检测按钮状态,最少选中一个
- (void)checkButtonState{ int selectCount = ;
UIButton* selectedBtn = nil;
for(int i=;i < _tagArray.count; i++){
UIButton* btn = (UIButton*)[self viewWithTag:+i];
if(btn.selected){
selectCount++;
selectedBtn = btn;
}
}
if (selectCount == ) {
// 只有一个就把这一个给禁用手势
selectedBtn.userInteractionEnabled = NO;
}else{
// 解除禁用手势
for(int i=;i < _tagArray.count; i++){
UIButton* btn = (UIButton*)[self viewWithTag:+i];
if(!btn.userInteractionEnabled){
btn.userInteractionEnabled = YES;
}
}
}
} // 根据颜色生成UIImage
- (UIImage*)imageWithColor:(UIColor*)color{ CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
// 开始画图的上下文
UIGraphicsBeginImageContext(rect.size); // 设置背景颜色
[color set];
// 设置填充区域
UIRectFill(CGRectMake(, , rect.size.width, rect.size.height)); // 返回UIImage
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
// 结束上下文
UIGraphicsEndImageContext();
return image;
} #pragma mark - Event // 标签按钮点击事件
- (void)selectdButton:(UIButton*)btn{ btn.selected = !btn.selected; // 检测按钮状态,最少选中一个
[self checkButtonState];
} @end

好了,大家如果有什么地方看不明白的,留言给我就行~~

IOS动态自适应标签实现的更多相关文章

  1. jQuery计算文本宽度和input标签根据输入字符动态自适应宽度的实现

    jQuery计算文本宽度的原理是利用html提供的<pre>标签,向dom中动态添加<pre>标签,标签里的内容就是要测试长度的文本,获取完长度之后再删除刚才添加的<pr ...

  2. js 面向对象 动态添加标签

    有点逻辑 上代码 thml布局 点击查看代码 <!DOCTYPE html> <html lang="en"> <head> <meta ...

  3. EasyUI创建异步树形菜单和动态添加标签页tab

    创建异步树形菜单 创建树形菜单的ul标签 <ul class="easyui-tree" id="treeMenu"> </ul> 写j ...

  4. EasyUI中动态生成标签页

    这是最近学到的内容,当时是有思路但是不知道怎么获取当前的点击对象,就没有实现功能,通过更深入的学习,我知道了不仅仅是Java,Oracle中有一个this,同样的EasyUI中也存在一个this,来获 ...

  5. iOS动态部署方案

    转载: iOS动态部署方案 前言 这里讨论的动态部署方案,就是指通过不发版的方式,将新的内容.新的业务流程部署进已发布的App.因为苹果的审核周期比较长,而且苹果的限制比较多,业界在这里也没有特别多的 ...

  6. 9.mybatis动态SQL标签的用法

    mybatis动态SQL标签的用法   动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么 ...

  7. iframe高度动态自适应

    by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1294 一.前言碎碎念 ...

  8. iOS 键盘自适应(IQKeyboardManager)使用小结

    IQKeyboardManager Github地址 经常在开发一个应用程序,我们遇到了一个问题,iPhone的键盘上滑覆盖的UITextField / UITextView.IQKeyboardMa ...

  9. EasyUI 布局 - 动态添加标签页(Tabs)

    首先导入js <link rel="stylesheet" href="../js/easyui/themes/default/easyui.css"&g ...

随机推荐

  1. Kafka 0.10 SocketServer源代码分析

    1概要设计 Kafka SocketServer是基于Java NIO来开发的,采用了Reactor的模式,其中包含了1个Acceptor负责接受客户端请求,N个Processor负责读写数据,M个H ...

  2. Vue框架Element的事件传递broadcast和dispatch方法分析

    前言 最近在学习饿了么的Vue前端框架Element,发现其源码中大量使用了$broadcast和$dispatch方法,而Element使用的是Vue2.0版本,众所周知在Vue 1.0升级到2.0 ...

  3. 时间处理之strtotime

    strtotime (PHP 4, PHP 5, PHP 7)strtotime - 将任何英文文本的日期时间描述解析为 Unix 时间戳说明 int strtotime ( string $time ...

  4. 原生js实现轮播图

    原生js实现轮播图 很多网站上都有轮播图,但找到一个系统讲解的却很难,因此这里做一个简单的介绍,希望大家都能有所收获,如果有哪些不正确的地方,希望大家可以指出. 原理: 将一些图片在一行中平铺,然后计 ...

  5. 用phpcms如何将静态页面制作成企业网站(中)

    上篇博客中讲到了该修改网页的中间部分 中间的内容是这样的,有标题和内容,里面的内容被代码替代,运行起来就这样的 里面的内容就可以在后台管理那里添加 再来看代码部分 <div class=&quo ...

  6. ROM及其他知识

     ROM--Read Only Memory 中文意思是:只读存贮器  以前的游戏机用的都是卡带,里面是一块或几块集成电路芯片,游戏程序就是在生产厂家一次性写入这几块芯片,以后用户玩游戏的时候只能读出 ...

  7. 继续学习ant

    今天由于打电话,打了两个小时的电话,结果一下子错过了学习的时间段,表示很惭愧,不过查了一些资料,感觉还不错,明天继续学习吧! ant入门到精通Ant 的最完整build.xml解释ant实用实例Ant ...

  8. awk,sed文本处理案例

    #!/bin/bash ############################################################################# #针对一个多级目录下 ...

  9. p1221网络布线(最小生成树 Prim(普里母)算法) p1222 Watering Hole

    描述 Description 农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场.当然,他需要你的帮助.约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路 ...

  10. Ognl值栈对象及struts标签

    用户每次访问struts的action,都会创建一个Action对象.值栈对象.ActionContext对象:然后把Action对象放入值栈中: 最后再把值栈对象放入request中,传入jsp页面 ...