设计多选按钮ListChooseView

答应某位女屌丝而写的控件,效果还不错,开源给大家^_^!

效果图:

源码:

//
// ListChooseView.h
// ScrollChooseButton
//
// http://www.jikexueyuan.com/course/397.html
// http://www.cnblogs.com/YouXianMing/
//
// Created by YouXianMing on 14/12/23.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
// #import <UIKit/UIKit.h> @interface ListChooseView : UIView #pragma mark -
/**
* 按钮之间的间隙,不设置的话默认值为5
*/
@property (nonatomic, assign) CGFloat gap; /**
* 按钮值偏移量
*/
@property (nonatomic, assign) CGFloat buttonOffset; #pragma mark -
/**
* 标题数组
*/
@property (nonatomic, strong) NSArray *titleArray; /**
* 已经选择的标题的数组
*/
@property (nonatomic, strong) NSArray *chosenTitleArray; #pragma mark -
/**
* 按钮的字体
* 正常状态下的按钮色值(不设定则为白色)
* 高亮状态下的按钮色值(不设定则没有值)
* 按钮线条粗细(不设定默认值为1)
* 按钮线条颜色(不设定默认值为黑色)
* 按钮圆角
*/
@property (nonatomic, strong) UIFont *buttonFont;
@property (nonatomic, strong) UIColor *normalStateButtonTitleColor;
@property (nonatomic, strong) UIColor *highlightedStateButtonTitleColor;
@property (nonatomic, assign) CGFloat lineWidth;
@property (nonatomic, strong) UIColor *lineColor;
@property (nonatomic, assign) CGFloat cornerRadius; #pragma mark -
/**
* 选中状态下显示的图片
* 图片横线偏移量
* 图片纵向偏移量
*/
@property (nonatomic, strong) UIImage *selectedImage;
@property (nonatomic, assign) CGFloat offsetX;
@property (nonatomic, assign) CGFloat offsetY; #pragma mark - /**
* 选中的标题
*/
@property (nonatomic, strong, readonly) NSMutableArray *selectedIndex; /**
* 配置好所有参数后就创建出控件
*/
- (void)createListChooseView; @end
//
// ListChooseView.m
// ScrollChooseButton
//
// Created by YouXianMing on 14/12/23.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
// #import "ListChooseView.h" typedef enum : NSUInteger {
UIBUTTON = 0x19871220, // [YouXingMing birthDay]
UIIMAGEVIEW = 0x88888888,
} EnumListChooseView; @interface ListChooseView () @property (nonatomic, assign) CGFloat buttonHeight; // 按钮的高度
@property (nonatomic, assign) CGFloat totalLength; // 总长度 @property (nonatomic, strong) UIScrollView *scrollView; // 用于滑动的scrollView
@property (nonatomic, strong) NSMutableArray *buttonWidthArray; // 存储所有按钮的宽度 @property (nonatomic, strong) NSMutableArray *allButtonsState; // 存储所有按钮点击状态
@property (nonatomic, strong) NSMutableArray *selectedIndex; @end @implementation ListChooseView - (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 添加scrollView
_scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
_scrollView.layer.masksToBounds = NO;
_scrollView.showsHorizontalScrollIndicator = NO;
[self addSubview:_scrollView]; // 按钮高度
_buttonHeight = frame.size.height; // 存储所有按钮宽度
_buttonWidthArray = [NSMutableArray array];
}
return self;
} - (void)createListChooseView {
// 没有一个元素则直接返回
if (_titleArray.count == ) {
NSLog(@"没有一个元素可供选择");
return;
} // 存储所有按钮中文本的宽度
for (int i = ; i < _titleArray.count; i++) {
// 必须是字符串
if ([_titleArray[i] isKindOfClass:[NSString class]]) {
CGFloat buttonWidth = [self string:_titleArray[i] widthWithLabelFont:self.buttonFont];
[_buttonWidthArray addObject:@(buttonWidth)];
} else {
NSLog(@"有非字符串的东西混入");
return;
}
} // 所有按钮点击状态初始化(默认为NO,没有勾选)
self.allButtonsState = [NSMutableArray array];
for (int i = ; i < _titleArray.count; i++) {
[self.allButtonsState addObject:@(NO)];
} // 选择按钮列表
if (self.chosenTitleArray) {
for (int i = ; i < self.chosenTitleArray.count; i++) {
// 获取标题
NSString *title = self.chosenTitleArray[i]; // 找到匹配的就替换
for (int j = ; j < _titleArray.count; j++) {
if ([_titleArray[j] isEqualToString:title]) {
[self.allButtonsState replaceObjectAtIndex:j withObject:@(YES)];
break;
}
}
}
} // 创建出控件
CGFloat tmpXpositon = ;
for (int i = ; i < _titleArray.count; i++) { CGFloat viewGap = (self.gap == ? : self.gap); if (i == ) {
tmpXpositon += ;
} else {
tmpXpositon += [_buttonWidthArray[i - ] floatValue] + self.buttonOffset;
} // 临时的view,用于存储button
UIView *tmpView = [[UIView alloc] initWithFrame:CGRectMake( + i*viewGap + tmpXpositon,
,
[_buttonWidthArray[i] floatValue] + self.buttonOffset,
_buttonHeight)];
// 配置button
UIButton *tmpButton = [[UIButton alloc] initWithFrame:tmpView.bounds];
[tmpView addSubview:tmpButton]; // 按钮tag值
tmpButton.tag = UIBUTTON + i; if (self.selectedImage) { // 添加选中的图片
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.selectedImage]; CGRect rect = imageView.frame;
rect.origin.x = [_buttonWidthArray[i] floatValue] + self.offsetX;
rect.origin.y = self.offsetY;
imageView.frame = rect; imageView.tag = UIIMAGEVIEW + i;
if ([self.allButtonsState[i] boolValue] == YES) {
imageView.alpha = ; // 显示图片
} else {
imageView.alpha = ; // 隐藏图片
} [tmpView addSubview:imageView];
}
[tmpButton setTitle:_titleArray[i] forState:UIControlStateNormal]; // 设置标题
if (self.buttonFont) {
tmpButton.titleLabel.font = self.buttonFont; // 设置按钮字体
}
if (self.normalStateButtonTitleColor) {
[tmpButton setTitleColor:self.normalStateButtonTitleColor forState:UIControlStateNormal]; // 设置按钮正常标题颜色
}
if (self.highlightedStateButtonTitleColor) {
[tmpButton setTitleColor:self.highlightedStateButtonTitleColor forState:UIControlStateHighlighted]; // 高亮标题颜色
}
tmpButton.layer.borderWidth = (self.lineWidth <= ? : self.lineWidth); // 设置按钮边缘粗细
if (self.lineColor) {
tmpButton.layer.borderColor = self.lineColor.CGColor; // 设定线条颜色
}
if (self.cornerRadius > ) {
tmpButton.layer.cornerRadius = self.cornerRadius; // 设定圆角
} [tmpButton addTarget:self
action:@selector(buttonsEvent:)
forControlEvents:UIControlEventTouchUpInside]; // 计算总长度(最后一次循环)
if (_titleArray.count - == i) {
_totalLength = tmpView.frame.origin.x + [_buttonWidthArray[i] floatValue] + self.buttonOffset;
} [self.scrollView addSubview:tmpView];
} self.scrollView.contentSize = CGSizeMake(_totalLength, _buttonHeight);
} - (void)buttonsEvent:(UIButton *)button { // 第几个按钮
NSInteger index = button.tag - UIBUTTON;
BOOL selectedButtonState = [_allButtonsState[index] boolValue];
[_allButtonsState replaceObjectAtIndex:index withObject:@(!selectedButtonState)]; // 选择了几个按钮
self.selectedIndex = [NSMutableArray arrayWithArray:_allButtonsState]; // 更新按钮上面的图标
[self updateButtonImage:button index:index];
} - (void)updateButtonImage:(UIButton *)button index:(NSInteger)index{
if ([_allButtonsState[index] boolValue] == NO) {
UIImageView *tmpView = (UIImageView *)[[button superview] viewWithTag:UIIMAGEVIEW + index];
[UIView animateWithDuration:0.15 animations:^{
tmpView.alpha = .f;
}];
} else {
UIImageView *tmpView = (UIImageView *)[[button superview] viewWithTag:UIIMAGEVIEW + index];
[UIView animateWithDuration:0.15 animations:^{
tmpView.alpha = .f;
}];
}
} /**
* 计算
*
* @param string 文本
* @param font 字体
*
* @return 宽度
*/
- (CGFloat)string:(NSString *)string widthWithLabelFont:(UIFont *)font {
CGFloat retHeight = ; if (string.length == ) {
retHeight = ;
} else { // 字体
NSDictionary *attribute = @{NSFontAttributeName: [UIFont systemFontOfSize:.f]};
if (font) {
attribute = @{NSFontAttributeName: font};
} // 尺寸
CGSize retSize = [string boundingRectWithSize:CGSizeMake(MAXFLOAT, )
options:
NSStringDrawingTruncatesLastVisibleLine |
NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:attribute
context:nil].size; retHeight = retSize.width;
} return retHeight;
} @end

使用时候的源码:

//
// ViewController.m
// ScrollChooseButton
//
// Created by YouXianMing on 14/12/23.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
// #import "ViewController.h"
#import "ListChooseView.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; self.view.backgroundColor = [UIColor blackColor]; [self createListChooseView];
} - (void)createListChooseView {
ListChooseView *chooseView = [[ListChooseView alloc] initWithFrame:CGRectMake(, , , )];
chooseView.center = self.view.center;
chooseView.buttonOffset = ;
chooseView.gap = .f;
chooseView.cornerRadius = .f;
chooseView.buttonFont = [UIFont systemFontOfSize:.f];
chooseView.normalStateButtonTitleColor = [UIColor grayColor];
chooseView.highlightedStateButtonTitleColor = [UIColor cyanColor];
chooseView.lineColor = [UIColor grayColor];
chooseView.selectedImage = [UIImage imageNamed:@"selected"];
chooseView.offsetY = -;
chooseView.offsetX = .f;
chooseView.titleArray = @[@"女武神", @"瓦尔基里", @"YouXianMing", @"小苹果", @"梦醒时分"];
chooseView.chosenTitleArray = @[@"YouXianMing"];
[chooseView createListChooseView]; [self.view addSubview:chooseView];
} @end

需要注意的地方:

设计多选按钮ListChooseView的更多相关文章

  1. .NET开源工作流RoadFlow-表单设计-复选按钮组

    复选按钮组的设置与单选按钮组的设置相同,只是表现形式为:<input type="checkbox"/>

  2. 设计多选一按钮ChooseOnlyButton

    设计多选一按钮ChooseOnlyButton 效果: 源码: ChooseOnlyButton.h 与 ChooseOnlyButton.m // // ChooseOnlyButton.h // ...

  3. js动态获取子复选项并设计全选及提交

    在做项目的时候,会遇到根据父选项,动态的获取子选项,并列出多个复选框,提交时,把选中的合并成一个字符提交后台 本章将讲述如何通过js控制实现该操作: 1:设计父类别为radio,为每一个radio都加 ...

  4. Chapter 4. Button, Checkbutton, and Radiobutton Widgets 按钮,复选按钮,单选按钮

    Chapter 4. Button, Checkbutton, and Radiobutton Widgets   按钮,复选按钮,单选按钮 几乎所有的Perl/Tk 应用使用按钮以这样或者那样的方式 ...

  5. 单选按钮、复选按钮——axure线框图部件库介绍

    有时候发现这做事情坚持下来是一件很不容易的,写教程也一样,不过听到很多朋友对我说 这个全部是图片的教程 对他们入门帮助很多,我就想想 在坚持坚持把基础部分先完善了! 1. 简单的问卷调查: 您的性别? ...

  6. 《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)

    1.简介 在实际自动化测试过程中,我们同样也避免不了会遇到单选和多选的测试,特别是调查问卷或者是答题系统中会经常碰到.因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助 ...

  7. 《手把手教你》系列技巧篇(三十四)-java+ selenium自动化测试-单选和多选按钮操作-中篇(详解教程)

    1.简介 今天这一篇宏哥主要是讲解一下,如何使用list容器来遍历单选按钮.大致两部分内容:一部分是宏哥在本地弄的一个小demo,另一部分,宏哥是利用JQueryUI网站里的单选按钮进行实战. 2.d ...

  8. 《手把手教你》系列技巧篇(三十五)-java+ selenium自动化测试-单选和多选按钮操作-下篇(详解教程)

    1.简介 今天这一篇宏哥主要是讲解一下,如何使用list容器来遍历多选按钮.大致两部分内容:一部分是宏哥在本地弄的一个小demo,另一部分,宏哥是利用JQueryUI网站里的多选按钮进行实战. 2.d ...

  9. 《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)

    1.简介 前边几篇文章是宏哥自己在本地弄了一个单选和多选的demo,然后又找了网上相关联的例子给小伙伴或童鞋们演示了一下如何自动化测试,这一篇宏哥在网上找了一个问卷调查,给小伙伴或童鞋们来演示一下.上 ...

随机推荐

  1. Visual Studio使用阿里云Code Git服务器的常见问题

    使用Github的服务器太慢,阿里的https://code.aliyun.com的国内服务器还是很快的.但是使用阿里的Git服务器总是有些地方出问题,现记录下常见的问题: 1.如提示源码已在TFS管 ...

  2. I/O模式总结

    进程读取数据时要经过两个阶段: 1.等待内核准备数据: 2.将内核缓冲区中的数据复制到进程缓冲区中. 一.阻塞IO 进程会阻塞在等待内核准备数据和数据从内核空间复制到用户空间这两个阶段. 二.非阻塞I ...

  3. C#语法之Linq查询基础一

    Linq做.Net开发的应该都用过,有些地方很复杂的逻辑用Linq很方便的解决.对于Linq to object.Linq to xml.Linq to sql.Linq to Entity(EF)都 ...

  4. Content Negotiation using Spring MVC

    There are two ways to generate output using Spring MVC: You can use the RESTful @ResponseBody approa ...

  5. .NET环境下使用水晶报表

    .NET环境下使用水晶报表 听语音 | 浏览:3280 | 更新:2013-12-20 13:36 1 2 3 4 5 6 7 分步阅读 水晶报表(Crystal Reports)-商务智能软件,通常 ...

  6. CodeBlocks "no such file or directory" 错误解决方案(创建类找不到头文件)

    在CodeBlocks下,有时候需要自己定义类,当然就要添加相应的头文件,但添加进去的头文件明明包含在项目中了, 但编译时还是会报错:no such file or directory;这是为什么呢? ...

  7. jquery序列化from表单使用ajax提交返回json数据(使用struts2注解result type = json)

    1.action类引入struts2的"json-default"拦截器栈 @ParentPackage("json-default") //示例 @Paren ...

  8. 打造自己的LinQProvider(四)

    打造自己的LinqProvider *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

  9. [日常] MySQL内存不足启动失败的解决方法

    1.启动mysql时,一直不成功,查看错误日志 /var/log/mysql/error.log 2.主要的错误信息有如下几条: [ERROR] InnoDB: mmap(136151040 byte ...

  10. pch文件配置

    配置.pch文件 刚上手 Xcode6 的人,总会发现之前在 6 之前常常会在“利用名-Prefix.pch”这个文件中来配置我们全局要用到的头文件,但是 xcode6 没有了,人家说,这类东西有时候 ...