iOS 开发之排序按钮

释放双眼,带上耳机,听听看~!

前言

排序按钮是实际开发中比较常见的一种控件,最近我也遇到了,今天简单分享下。

虽然功能简单,但是保证你看了不亏,尤其是对UI这块比较薄弱的同学来说。

OK,先看图:

简单描述一下:

按钮一共有三种状态:非选中、选中升序、选中降序。

按钮的三种状态

点击按钮时有两种情况:

  1. 按钮原本处于非选中状态,点击,切换到选中状态,其状态变为升序。
  2. 按钮原本就处于选中状态,再点击一下,则切换其排序状态(升变降、降变升)。

不同状态对应不同的icon,如果没有UI,可以去iconfont 找图标,输入关键词如“上下箭头”就可以找到你需要的icon。

基本思路

继承UIButton,直接在button上放view,设置约束,根据按钮的状态设置对应的图片。

PS:自定义按钮最灵活的做法就是直接在button上放view(在不需要纠结内存和view层级的情况下),简单粗暴、随心所欲。

完整代码

.h文件:

#import <UIKit/UIKit.h>
@interface CQSortButton : UIButton
/** 按钮文本 */
@property (nonatomic, copy) NSString *title;
/** 是否是升序 */
@property (nonatomic, assign, readonly, getter=isAscending) BOOL ascending;
@end

.m文件:

#import "CQSortButton.h"
@interface CQSortButton ()
/** 文本label */
@property (nonatomic, strong) UILabel *cq_titleLabel;
/** 箭头imageView */
@property (nonatomic, strong) UIImageView *cq_arrowImageView;
@end
@implementation CQSortButton
#pragma mark - 构造方法
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupUI];
}
return self;
}
#pragma mark - UI搭建
- (void)setupUI {
self.layer.borderColor = [UIColor blackColor].CGColor;
self.layer.borderWidth = 1;
// 文本和图片的父view
UIView *contentView = [[UIView alloc] init];
[self addSubview:contentView];
contentView.userInteractionEnabled = NO;
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.centerX.mas_equalTo(self);
make.left.mas_greaterThanOrEqualTo(self).mas_offset(3);
make.right.mas_lessThanOrEqualTo(self).mas_offset(-3);
}];
// 文本
self.cq_titleLabel = [[UILabel alloc] init];
[contentView addSubview:self.cq_titleLabel];
self.cq_titleLabel.font = [UIFont boldSystemFontOfSize:13];
self.cq_titleLabel.adjustsFontSizeToFitWidth = YES;
[self.cq_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.left.mas_offset(0);
}];
// 图片
self.cq_arrowImageView = [[UIImageView alloc] init];
[contentView addSubview:self.cq_arrowImageView];
self.cq_arrowImageView.image = [UIImage imageNamed:@"up_down"];
[self.cq_arrowImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(20, 20));
make.centerY.mas_equalTo(contentView);
make.left.mas_equalTo(self.cq_titleLabel.mas_right);
make.right.mas_equalTo(contentView);
}];
}
#pragma mark - 赋值选中状态
- (void)setSelected:(BOOL)selected {
//// 注意:
//// selected 表示你要赋值的状态
//// super.selected 表示当前处于的状态
if (selected) { // 即将设置成选中状态
if (super.selected) { // 如果原本就处于选中状态
// 那么就切换筛选状态
_ascending = !_ascending;
if (_ascending) {
// 升序
self.cq_arrowImageView.image = [UIImage imageNamed:@"red_arrow_up"];
} else {
// 降序
self.cq_arrowImageView.image = [UIImage imageNamed:@"red_arrow_down"];
}
} else { // 如果之前不是选中状态
// 那么设置成选中的默认排序状态:升序
_ascending = YES;
self.cq_arrowImageView.image = [UIImage imageNamed:@"red_arrow_up"];
}
} else { // 即将设置成非选中状态
// 设置成非选中状态的图片
self.cq_arrowImageView.image = [UIImage imageNamed:@"up_down"];
}
// 最后再赋值
[super setSelected:selected];
}
#pragma mark - 赋值文本
- (void)setTitle:(NSString *)title {
_title = title;
self.cq_titleLabel.text = title;
}
@end

使用:

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSArray *titleArray = @[@"同比", @"销售额", @"?", @"文字有点多啊"];
NSMutableArray *buttonArray = [NSMutableArray array];
for (int i = 0; i < 4; i++) {
CQSortButton *button = [[CQSortButton alloc] init];
[self.view addSubview:button];
button.title = titleArray[i];
button.tag = CQSortButtonBeginTag + i;
[button addTarget:self action:@selector(sortButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[buttonArray addObject:button];
}
// 按钮等宽依次排列
[buttonArray mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:0 leadSpacing:0 tailSpacing:0];
[buttonArray mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
make.height.mas_equalTo(40);
}];
}
- (void)sortButtonClicked:(CQSortButton *)sender {
for (int i = 0; i < 4; i++) {
CQSortButton *button = [self.view viewWithTag:(CQSortButtonBeginTag + i)];
button.selected = (button.tag == sender.tag);
}
NSLog(@"第%ld个按钮点击,状态:%@", (long)(sender.tag-CQSortButtonBeginTag), sender.isAscending ? @"升序" : @"降序");
}

知识点及细节

1.如何让两个view整体居中并且不超出父view?

创建父view是关键。

先创建一个父view,这个父view居中于button,左右不设置固定约束,再将两个view放在父view上,左边的view与父view左对齐,右边的view与父view右对齐,左边的view与右边的view水平方向约束确定,撑开父view:

// 文本和图片的父view
UIView *contentView = [[UIView alloc] init];
[self addSubview:contentView];
[contentView addSubview:self.cq_titleLabel];
[contentView addSubview:self.cq_arrowImageView];
[self.cq_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.left.mas_offset(0);
}];
[self.cq_arrowImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(20, 20));
make.centerY.mas_equalTo(contentView);
make.left.mas_equalTo(self.cq_titleLabel.mas_right);
make.right.mas_equalTo(contentView);
}];

不超出父view(此处指button)用mas_greaterThanOrEqualTo和mas_lessThanOrEqualTo即可:

[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.centerX.mas_equalTo(self);
make.left.mas_greaterThanOrEqualTo(self).mas_offset(3);
make.right.mas_lessThanOrEqualTo(self).mas_offset(-3);
}];

2.readonly的使用

/** 是否是升序 */
@property (nonatomic, assign, readonly, getter=isAscending) BOOL ascending;

为什么这里要用readonly?

因为这个属性的改变只能是通过内部(自身的.m)改变,而不能通过外部改变,或者说这个属性只是用来反映按钮的一个状态,就像UIScrollView的decelerating属性一样,只是反映scrollView正在减速,不能通过调用scrollView.decelerating = YES让它主动减速。

// returns YES if user isn't dragging (touch up) but scroll view is still moving
@property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating;

总结一下就是readonly适用于只用来反映对象的状态、特征或特性的属性。

你可以找几个苹果官方文档里的readonly属性好好感受一下。

3.如何使用masonry等宽等间距排列控件?

用masory提供的mas_distributeViewsAlongAxis方法:

// 按钮等宽依次排列[buttonArray mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:0 leadSpacing:0 tailSpacing:0];
[buttonArray mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
make.height.mas_equalTo(40);
}];

关于这个方法的更多使用可以参考这篇文章:

iOS Masonry 等间隔或等宽高排列多个控件,很实用的技能,建议熟练掌握。
需要注意的是调用mas_distributeViewsAlongAxis这个方法的数组其元素个数必须bigger than one,否则没有效果,masonry源码截取:

- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing {    if (self.count < 2) {        NSAssert(self.count>1,@"views to distribute need to bigger than one");        return;
}
......
}

所以实际开发中如果你是获取后台的数组来展示的话,务必先判断数组的count。

Demo地址

人已赞赏
iOS文章

iOS MJExtension框架解决模型中存在系统的关键字或方法名

2020-5-3 4:03:05

iOS文章

iOS禁止侧滑返回上个页面

2020-5-3 5:18:16

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索