版本
Xcode 9.1
繼承關(guān)系:
UIButton : UIControl : UIView : UIResponder : NSObject
一、創(chuàng)建方法
通常,我們創(chuàng)建一個(gè)對(duì)象會(huì)使用[[class alloc] init];方法,但對(duì)于UIButton是不推薦使用此方法的。原因有二:
- UIButton有個(gè)按鈕樣式屬性buttonType需要在初始化的時(shí)候設(shè)定好,代碼后期無法改變。假如使用alloc創(chuàng)建,那么buttonType默認(rèn)為Custom模式。(關(guān)于buttonType詳見后文)
- MRC下,如果使用 [[UIButton alloc] init]的方式,需要進(jìn)行release釋放操作;如果使用[UIButton buttonWithType:(UIButtonType)]這種方式,不需要進(jìn)行release操作。
所以,代碼創(chuàng)建UIButton方法為:
[UIButton buttonWithType:(UIButtonType)]
二、按鈕樣式(UIButtonType)
UIButtonType有六種枚舉類型,對(duì)應(yīng)外觀如下:
之所以選擇樣式,是為了使用該樣式下已經(jīng)默認(rèn)設(shè)置好的一些屬性。
如Add Contact是一個(gè)“+”添加圖形。而Detail Disclosure、Info Light及Info Dark都是一個(gè)“i”信息圖形,Info Light和Info Dark這倆貨之間我實(shí)在找不到有什么異樣,但是這倆貨與Detail Disclosure或者其他樣式的區(qū)別是:這倆貨默認(rèn)屬性showsTouchWhenHighlighted=YES,這就使得在點(diǎn)擊按鈕的時(shí)候(高亮狀態(tài)),這倆貨會(huì)散發(fā)出白色的光芒!將背景色調(diào)成黑色看看效果:
最后來說說System和Custom這兩個(gè)樣式。對(duì)于System樣式,系統(tǒng)為我們預(yù)設(shè)了一些屬性(詳見下文對(duì)比部分)。Custom顧名思義是自定義的,可設(shè)置更多屬性。如果我們?cè)趕toryboard中設(shè)置Detail Disclosure、Info Light、Info Dark或者Add Contact按鈕的title、backgroundImage等屬性,會(huì)發(fā)現(xiàn)他們馬上變成Custom樣式;而如果設(shè)置了所有非Custom按鈕的image(前景圖片)屬性,那么這些按鈕也都將變成Custom樣式。說明Custom可操作的屬性還是比較多的。
System和Custom樣式對(duì)比:
1. 對(duì)于字體顏色
System默認(rèn)普通狀態(tài)下為藍(lán)色;Custom默認(rèn)白色。
2. 對(duì)于前景image
Custom樣式下可以顯示前景圖片,見圖Custom;System樣式不能顯示前景圖片,變成了圖System這衰樣...
3. 對(duì)于屬性adjustsImageWhenHighlighted
@property(nonatomic) BOOL adjustsImageWhenHighlighted; // default is YES. if YES, image is drawn darker when highlighted(pressed)
從官方注釋中可以看到,adjustsImageWhenHighlighted為YES時(shí),使得高亮狀態(tài)(按鈕按下)前景圖片和背景圖片均會(huì)變暗。如果將這個(gè)屬性值設(shè)為NO,按下按鈕圖片就不會(huì)變暗了。
經(jīng)我親測(cè),System樣式下adjustsImageWhenHighlighted默認(rèn)為NO,而Custom樣式下adjustsImageWhenHighlighted默認(rèn)才為YES,即此default值說的是Custom樣式。
按道理按下System樣式的按鈕,圖片應(yīng)該不會(huì)變暗才對(duì)(因?yàn)閍djustsImageWhenHighlighted默認(rèn)值為NO),但是它還是變暗了!這是為什么呢?還請(qǐng)接著看第4點(diǎn)。
4. 對(duì)于高亮狀態(tài)下
如果是System樣式,高亮狀態(tài)下(即按下按鈕)不止圖片變暗,文字也跟著變暗了。即使設(shè)置了adjustsImageWhenHighlighted=NO,或者設(shè)置了高亮狀態(tài)圖片與普通狀態(tài)圖片一致,也是不行。說明System在高亮狀態(tài)下還會(huì)改變另外一個(gè)屬性使得按鈕變暗。但是筆者卻找不出是哪個(gè)屬性改變了,估計(jì)看官已經(jīng)氣憤難當(dāng)磨刀霍霍了...
如果是Custom,文字不管在哪種狀態(tài)都不會(huì)變暗。而圖片會(huì)因?yàn)閍djustsImageWhenHighlighted默認(rèn)值為YES變暗,設(shè)置為NO就不變暗了。
三、按鈕屬性
一般來說,我們?cè)O(shè)置對(duì)象屬性都會(huì)使用點(diǎn)語法,但對(duì)于UIButton來說,有些屬性是不能使用點(diǎn)語法的。
設(shè)置屬性注意事項(xiàng)
1. UIButton的非私有屬性(繼承而來的屬性),可以使用點(diǎn)語法。
如:
btn.frame = CGRectMake(100, 100, 200, 50); // 設(shè)置位置尺寸
btn.backgroundColor = [UIColor purpleColor]; // 設(shè)置背景顏色
btn.alpha = 1.0f; // 設(shè)置透明度
btn.layer.cornerRadius = 5.0; // 設(shè)置圓角(5.0是圓角的弧度)
btn.layer.borderWidth = 1.0f; // 設(shè)置邊框?qū)挾? btn.layer.borderColor = [UIColor blackColor].CGColor; //設(shè)置邊框顏色
btn.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; // 設(shè)置垂直方向?qū)R方式
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; // 設(shè)置水平方向?qū)R模式
2. UIButton的私有屬性大多為只讀,不能使用點(diǎn)語法進(jìn)行set設(shè)置。
UIButton中所有只讀屬性:
@property(nonatomic,readonly) UIButtonType buttonType;
@property(nullable, nonatomic,readonly,strong) NSString *currentTitle; // normal/highlighted/selected/disabled. can return nil
@property(nonatomic,readonly,strong) UIColor *currentTitleColor; // normal/highlighted/selected/disabled. always returns non-nil. default is white(1,1)
@property(nullable, nonatomic,readonly,strong) UIColor *currentTitleShadowColor; // normal/highlighted/selected/disabled.
@property(nullable, nonatomic,readonly,strong) UIImage *currentImage; // normal/highlighted/selected/disabled. can return nil
@property(nullable, nonatomic,readonly,strong) UIImage *currentBackgroundImage; // normal/highlighted/selected/disabled. can return nil
@property(nullable, nonatomic,readonly,strong) NSAttributedString *currentAttributedTitle NS_AVAILABLE_IOS(6_0); // normal/highlighted/selected/disabled. can return nil
@property(nullable, nonatomic,readonly,strong) UILabel *titleLabel NS_AVAILABLE_IOS(3_0);
@property(nullable, nonatomic,readonly,strong) UIImageView *imageView NS_AVAILABLE_IOS(3_0);
3. UIButton有幾種顯示狀態(tài)(普通、高亮、選中等),每種狀態(tài)對(duì)應(yīng)的某些屬性是不同的,如果使用點(diǎn)語法就無法指明是哪種狀態(tài)下的屬性
比如設(shè)置以下屬性的時(shí)候需同時(shí)表明是在哪個(gè)狀態(tài)(State):
// 設(shè)置標(biāo)題
- (void)setTitle:(nullable NSString *)title forState:(UIControlState)state; // default is nil. title is assumed to be single line
// 設(shè)置標(biāo)題顏色
- (void)setTitleColor:(nullable UIColor *)color forState:(UIControlState)state UI_APPEARANCE_SELECTOR; // default if nil. use opaque white
// 設(shè)置標(biāo)題陰影顏色
- (void)setTitleShadowColor:(nullable UIColor *)color forState:(UIControlState)state UI_APPEARANCE_SELECTOR; // default is nil. use 50% black
// 設(shè)置前景圖片
- (void)setImage:(nullable UIImage *)image forState:(UIControlState)state; // default is nil. should be same size if different for different states
// 設(shè)置背景圖片
- (void)setBackgroundImage:(nullable UIImage *)image forState:(UIControlState)state UI_APPEARANCE_SELECTOR; // default is nil
// 設(shè)置帶屬性的標(biāo)題(NSAttributedString類型),設(shè)置麻煩不常用。
- (void)setAttributedTitle:(nullable NSAttributedString *)title forState:(UIControlState)state NS_AVAILABLE_IOS(6_0); // default is nil. title is assumed to be single line
讀取屬性
1. 獲取當(dāng)前狀態(tài)的屬性
使用點(diǎn)語法獲取只讀屬性,如:
btn. currentTitle、btn. currentImage等等
2. 獲取指定狀態(tài)的屬性
使用對(duì)象方法返回屬性:
- (nullable NSString *)titleForState:(UIControlState)state; // these getters only take a single state value
- (nullable UIColor *)titleColorForState:(UIControlState)state;
- (nullable UIColor *)titleShadowColorForState:(UIControlState)state;
- (nullable UIImage *)imageForState:(UIControlState)state;
- (nullable UIImage *)backgroundImageForState:(UIControlState)state;
- (nullable NSAttributedString *)attributedTitleForState:(UIControlState)state NS_AVAILABLE_IOS(6_0);
內(nèi)容對(duì)齊方式
因?yàn)閁IButton繼承自UIControl,而UIControl提供兩個(gè)屬性UIControlContentHorizontalAlignment和UIControlContentVerticalAlignment分別用來設(shè)置水平方向和垂直方向的對(duì)齊方式,對(duì)應(yīng)效果如下:
UIButton中image與backgroundImage區(qū)別
由于System樣式的按鈕不顯示前景圖片(前文有演示),因此以下均是對(duì)Custom樣式按鈕進(jìn)行探討。
1. 層級(jí)關(guān)系
創(chuàng)建一個(gè)帶有標(biāo)題title,前景圖片image和背景圖片backgroundImage的按鈕如下:
運(yùn)行代碼,然后捕捉視圖的層級(jí)關(guān)系:
或者直接點(diǎn)擊Xcode底部紅框內(nèi)按鈕,然后可以查看當(dāng)前視圖的層級(jí)關(guān)系:
小結(jié)一下:
- 視圖Z軸方向由里向外依次為backgroundImage--> image-->title
- image默認(rèn)居左,title默認(rèn)居右
2. 內(nèi)容模式
backgroundImage的內(nèi)容模式(contentMode)默認(rèn)為UIViewContentModeScaleToFill,backgroundImage會(huì)跟隨按鈕的大小的改變而改變,也就是說背景圖片始終等于按鈕尺寸。
對(duì)于image就比較怪:當(dāng)圖片的寬(或高)小于按鈕尺寸時(shí),image顯示的是原始寬(或高);當(dāng)圖片寬(或高)大于按鈕尺寸時(shí),image被壓縮到與button等寬(或高)的尺寸。這種內(nèi)容模式我叫不上名兒來。。。
對(duì)于image或者backgroundImage的contentMode屬性,蘋果沒有提供修改的途徑(至少我沒找到)。所以當(dāng)我們使用image的時(shí)候,最好先調(diào)好尺寸,對(duì)于比較大的圖片,先進(jìn)行必要的壓縮裁切。(不過筆者通常不會(huì)這么干,如果需要自定義比較高的button,我就直接用view來做外觀顯示,然后再套上一個(gè)透明的button~)
總結(jié)
- 按鈕的Z軸方向由里向外依次為backgroundImage--> image-->title
- image默認(rèn)居左,title默認(rèn)居右
- backgroundImage尺寸永遠(yuǎn)等于按鈕尺寸
- 對(duì)于image:當(dāng)圖片的寬(或高)小于按鈕尺寸時(shí),image顯示的是原始寬(或高);當(dāng)圖片寬(或高)大于按鈕尺寸時(shí),image被壓縮到與button等寬(或高)的尺寸。
- image和backgroundImage的contentMode屬性無法修改。
四、控制狀態(tài)(UIControlState)
在set按鈕的私有屬性的時(shí)候,通常會(huì)一并forState指明在哪個(gè)控制狀態(tài)。那么UIButton總共有幾個(gè)狀態(tài)呢?以下是UIControlState枚舉值:
typedef NS_OPTIONS(NSUInteger, UIControlState) {
UIControlStateNormal = 0, // 普通狀態(tài)(按下之前)
UIControlStateHighlighted = 1 << 0, // 高亮狀態(tài)(按下ing)
UIControlStateDisabled = 1 << 1, // 失效狀態(tài)(enable=NO)
UIControlStateSelected = 1 << 2, // 選中狀態(tài)(selected=YES)
UIControlStateFocused NS_ENUM_AVAILABLE_IOS(9_0) = 1 << 3, // 聚焦?fàn)顟B(tài)(iOS9.0開始引入,應(yīng)該和3D Touch有關(guān))
UIControlStateApplication = 0x00FF0000, // additional flags available for application use(不明覺厲)
UIControlStateReserved = 0xFF000000 // 蘋果預(yù)留位,憋管它。。。
};
我們看到,與普通的枚舉不同,UIControlState是位枚舉。也就是說,按鈕可以同時(shí)擁有不止一個(gè)狀態(tài)!
- if(isSelected == NO),有兩種狀態(tài):UIControlStateNormal 和 UIControlStateHighlighted
- if(isSelected == YES),也有兩種狀態(tài) UIControlStateSelected 和 UIControlStateSelected | UIControlStateHighlighted
也就是說:當(dāng)沒有選中狀態(tài)下,按下的時(shí)候?qū)?yīng)高亮模式(UIControlStateHighlighted);而當(dāng)按鈕已經(jīng)是選中狀態(tài),此時(shí)再按下按鈕即對(duì)應(yīng)高亮模式位和選中模式(UIControlStateSelected | UIControlStateHighlighted)。
五、添加事件
前面鋪墊了這么多,接下來該講講UIButton的主要作用了——響應(yīng)事件。要響應(yīng)事件,首先需給button添加對(duì)指定事件的監(jiān)聽機(jī)制(add target/action),即添加事件。
UIButton能響應(yīng)的事件(UIControlEvents)有很多,枚舉值如下:
UIControlEventTouchDown // 單點(diǎn)觸摸按下(用戶點(diǎn)觸屏幕,或者又有新手指落下的時(shí)候)
UIControlEventTouchDownRepeat // 多點(diǎn)觸摸按下(點(diǎn)觸計(jì)數(shù)大于1:用戶按下第二、三、或第四根手指的時(shí)候)
UIControlEventTouchDragInside // 當(dāng)一次觸摸在控件內(nèi)拖動(dòng)
UIControlEventTouchDragOutside // 當(dāng)一次觸摸在控件外拖動(dòng)
UIControlEventTouchDragEnter // 當(dāng)一次觸摸從控件外拖動(dòng)到內(nèi)部
UIControlEventTouchDragExit // 當(dāng)一次觸摸從控件內(nèi)部拖動(dòng)到外部
UIControlEventTouchUpInside // 所有在控件之內(nèi)觸摸抬起
UIControlEventTouchUpOutside // 所有在控件之外觸摸抬起(點(diǎn)觸起始必須落在控件內(nèi)部才會(huì)發(fā)送通知)
UIControlEventTouchCancel // 所有觸摸取消事件(如一次觸摸因?yàn)榉派狭颂嗍种付蝗∠蛘弑簧湘i或者電話呼入打斷)
UIControlEventValueChanged // 當(dāng)控件的值發(fā)生改變
UIControlEventPrimaryActionTriggered NS_ENUM_AVAILABLE_IOS(9_0) // 當(dāng)控件的首要行為被觸發(fā),例如button的點(diǎn)擊事件,slider的滑動(dòng)事件(iOS9.0引入)
UIControlEventEditingDidBegin // 當(dāng)控件中文本開始編輯時(shí)
UIControlEventEditingChanged // 當(dāng)控件中文本發(fā)生改變時(shí)
UIControlEventEditingDidEnd // 當(dāng)控件中文本編輯結(jié)束時(shí)
UIControlEventEditingDidEndOnExit // 當(dāng)文本控件內(nèi)通過按下回車鍵(或等價(jià)行為)結(jié)束編輯時(shí)
UIControlEventAllTouchEvents // 所有觸摸事件均觸發(fā)通知
UIControlEventAllEditingEvents // 所有文本編輯事件均觸發(fā)通知
UIControlEventApplicationReserved // 蘋果預(yù)留給應(yīng)用使用,不去理會(huì)
UIControlEventSystemReserved // 蘋果預(yù)留給內(nèi)部框架使用,不去理會(huì)
UIControlEventAllEvents // 所有事件均觸發(fā)通知
添加事件:
/**
添加點(diǎn)擊事件
addTarget:(參數(shù)1) 響應(yīng)目標(biāo)(由誰來執(zhí)行響應(yīng)方法)
action:(參數(shù)2) 調(diào)用方法(即響應(yīng)事件)
forControlEvents:(參數(shù)3) 事件的類型
*/
[btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
響應(yīng)方法:
#pragma mark - 按鈕響應(yīng)方法
- (void)btnAction:(UIButton *)btn {
NSLog(@"點(diǎn)擊了按鈕");
}
示例
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 實(shí)例化一個(gè)UIButton
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
/* 設(shè)置屬性 */
btn.frame = CGRectMake(0, 0, 100, 80 ); // 設(shè)置位置尺寸
btn.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/2);
btn.backgroundColor = [UIColor purpleColor]; // 設(shè)置背景顏色
btn.alpha = 1.0f; // 設(shè)置透明度
btn.layer.cornerRadius = 5.0; // 設(shè)置圓角(5.0是圓角的弧度)
btn.layer.borderWidth = 1.0f; // 設(shè)置邊框?qū)挾? btn.layer.borderColor = [UIColor blackColor].CGColor; //設(shè)置邊框顏色
btn.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; // 設(shè)置垂直方向?qū)R方式
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; // 設(shè)置水平方向?qū)R模式
// 設(shè)置標(biāo)題文字
[btn setTitle:@"普通" forState:UIControlStateNormal];
[btn setTitle:@"高亮" forState:UIControlStateHighlighted];
[btn setTitle:@"選中" forState:UIControlStateSelected];
[btn setTitle:@"選中狀態(tài)下的高亮" forState:UIControlStateHighlighted|UIControlStateSelected];
// 設(shè)置前景圖
// [btn setImage:[UIImage imageNamed:@"11"] forState:UIControlStateNormal];
// 設(shè)置背景圖
[btn setBackgroundImage:[UIImage imageNamed:@"red"] forState:UIControlStateNormal];
[btn setBackgroundImage:[UIImage imageNamed:@"goodFilling"] forState:UIControlStateHighlighted];
[btn setBackgroundImage:[UIImage imageNamed:@"red"] forState:UIControlStateHighlighted|UIControlStateSelected];
[btn setBackgroundImage:[UIImage imageNamed:@"red"] forState:UIControlStateSelected];
/**
添加點(diǎn)擊事件
addTarget:(參數(shù)1) 響應(yīng)目標(biāo)(由誰來執(zhí)行響應(yīng)方法)
action:(參數(shù)2) 調(diào)用方法(即響應(yīng)事件)
forControlEvents:(參數(shù)3) 事件的類型
*/
[btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
// 添加btn到self.view
[self.view addSubview:btn];
}
#pragma mark - 按鈕響應(yīng)方法
- (void)btnAction:(UIButton *)btn {
NSLog(@"點(diǎn)擊了按鈕");
}
@end