欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS 控件封装(又名拧螺丝)之排序按钮的开发

程序员文章站 2023-11-18 16:58:16
前言 排序按钮是实际开发中比较常见的一种控件,最近我也遇到了,今天简单分享下。 虽然功能简单,但是保证你看了不亏,尤其是对ui这块比较薄弱的同学来说。 ok,...

前言

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

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

ok,先看图:

iOS 控件封装(又名拧螺丝)之排序按钮的开发

简单描述一下:

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

iOS 控件封装(又名拧螺丝)之排序按钮的开发

按钮的三种状态

点击按钮时有两种情况:

  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等宽等间距排列控件?

iOS 控件封装(又名拧螺丝)之排序按钮的开发

用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地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。