iOS 控件封裝(又名擰螺絲)之排序按鈕的開發(fā)
前言
排序按鈕是實(shí)際開發(fā)中比較常見的一種控件,最近我也遇到了,今天簡(jiǎn)單分享下。
雖然功能簡(jiǎn)單,但是保證你看了不虧,尤其是對(duì)UI這塊比較薄弱的同學(xué)來(lái)說(shuō)。
OK,先看圖:
簡(jiǎn)單描述一下:
按鈕一共有三種狀態(tài):非選中、選中升序、選中降序。
按鈕的三種狀態(tài)
點(diǎn)擊按鈕時(shí)有兩種情況:
- 按鈕原本處于非選中狀態(tài),點(diǎn)擊,切換到選中狀態(tài),其狀態(tài)變?yōu)樯颉?/li>
- 按鈕原本就處于選中狀態(tài),再點(diǎn)擊一下,則切換其排序狀態(tài)(升變降、降變升)。
不同狀態(tài)對(duì)應(yīng)不同的icon,如果沒(méi)有UI,可以去iconfont 找圖標(biāo),輸入關(guān)鍵詞如“上下箭頭”就可以找到你需要的icon。
基本思路
繼承UIButton,直接在button上放view,設(shè)置約束,根據(jù)按鈕的狀態(tài)設(shè)置對(duì)應(yīng)的圖片。
PS:自定義按鈕最靈活的做法就是直接在button上放view(在不需要糾結(jié)內(nèi)存和view層級(jí)的情況下),簡(jiǎn)單粗暴、隨心所欲。
完整代碼
.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 - 構(gòu)造方法 - (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 - 賦值選中狀態(tài) - (void)setSelected:(BOOL)selected { //// 注意: //// selected 表示你要賦值的狀態(tài) //// super.selected 表示當(dāng)前處于的狀態(tài) if (selected) { // 即將設(shè)置成選中狀態(tài) if (super.selected) { // 如果原本就處于選中狀態(tài) // 那么就切換篩選狀態(tài) _ascending = !_ascending; if (_ascending) { // 升序 self.cq_arrowImageView.image = [UIImage imageNamed:@"red_arrow_up"]; } else { // 降序 self.cq_arrowImageView.image = [UIImage imageNamed:@"red_arrow_down"]; } } else { // 如果之前不是選中狀態(tài) // 那么設(shè)置成選中的默認(rèn)排序狀態(tài):升序 _ascending = YES; self.cq_arrowImageView.image = [UIImage imageNamed:@"red_arrow_up"]; } } else { // 即將設(shè)置成非選中狀態(tài) // 設(shè)置成非選中狀態(tài)的圖片 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 = @[@"同比", @"銷售額", @"🙃", @"文字有點(diǎn)多啊"]; 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個(gè)按鈕點(diǎn)擊,狀態(tài):%@", (long)(sender.tag-CQSortButtonBeginTag), sender.isAscending ? @"升序" : @"降序"); }
知識(shí)點(diǎn)及細(xì)節(jié)
1.如何讓兩個(gè)view整體居中并且不超出父view?
創(chuàng)建父view是關(guān)鍵。
先創(chuàng)建一個(gè)父view,這個(gè)父view居中于button,左右不設(shè)置固定約束,再將兩個(gè)view放在父view上,左邊的view與父view左對(duì)齊,右邊的view與父view右對(duì)齊,左邊的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?
因?yàn)檫@個(gè)屬性的改變只能是通過(guò)內(nèi)部(自身的.m)改變,而不能通過(guò)外部改變,或者說(shuō)這個(gè)屬性只是用來(lái)反映按鈕的一個(gè)狀態(tài),就像UIScrollView的decelerating屬性一樣,只是反映scrollView正在減速,不能通過(guò)調(diào)用scrollView.decelerating = YES讓它主動(dòng)減速。
// returns YES if user isn't dragging (touch up) but scroll view is still moving @property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating;
總結(jié)一下就是readonly適用于只用來(lái)反映對(duì)象的狀態(tài)、特征或特性的屬性。
你可以找?guī)讉€(gè)蘋果官方文檔里的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); }];
關(guān)于這個(gè)方法的更多使用可以參考這篇文章:
iOS Masonry 等間隔或等寬高排列多個(gè)控件,很實(shí)用的技能,建議熟練掌握。
需要注意的是調(diào)用mas_distributeViewsAlongAxis這個(gè)方法的數(shù)組其元素個(gè)數(shù)必須bigger than one,否則沒(méi)有效果,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; } ...... }
所以實(shí)際開發(fā)中如果你是獲取后臺(tái)的數(shù)組來(lái)展示的話,務(wù)必先判斷數(shù)組的count。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
IOS 上架后出現(xiàn)90034代碼錯(cuò)誤問(wèn)題解決
這篇文章主要介紹了IOS 上架后出現(xiàn)90034代碼錯(cuò)誤問(wèn)題解決的相關(guān)資料,需要的朋友可以參考下2016-11-11IOS初始化控制器的實(shí)現(xiàn)方法總結(jié)
這篇文章主要介紹了IOS初始化控制器的實(shí)現(xiàn)方法總結(jié)的相關(guān)資料,這里提供兩種實(shí)現(xiàn)方法分別是ViewControllViewController方法和 ViewControllViewController 與 xib方法,需要的朋友可以參考下2017-10-10IOS應(yīng)用程序多語(yǔ)言本地化的兩種解決方案
本篇文章介紹了IOS應(yīng)用程序多語(yǔ)言本地化解決方案,這里整理了詳細(xì)的解決辦法,有需要的小伙伴可以參考下。2016-11-11iOS 動(dòng)畫 —— 禮花效果實(shí)例詳細(xì)
這篇文章主要介紹了iOS 動(dòng)畫 —— 禮花效果實(shí)例詳細(xì)的相關(guān)資料,需要的朋友可以參考下2016-09-09iOS開發(fā)實(shí)現(xiàn)隨機(jī)圖片驗(yàn)證碼封裝
這篇文章主要介紹了iOS開發(fā)實(shí)現(xiàn)隨機(jī)圖片驗(yàn)證碼封裝,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08