iOS---UIButton詳解及如何調(diào)整image和title的布局

@class UIImage, UIFont, UIColor, UIImageView, UILabel;

typedef NS_ENUM(NSInteger, UIButtonType) {

//以枚舉的形似表示---button的界面形式

UIButtonTypeCustom = 0,? ? ? ? ? ? ? ? ? ? ? ? // no button type

UIButtonTypeSystem NS_ENUM_AVAILABLE_IOS(7_0),? // standard system button

UIButtonTypeDetailDisclosure,

UIButtonTypeInfoLight,

UIButtonTypeInfoDark,

UIButtonTypeContactAdd,

UIButtonTypePlain API_AVAILABLE(tvos(11.0)) __IOS_PROHIBITED __WATCHOS_PROHIBITED, // standard system button without the blurred background view

UIButtonTypeRoundedRect = UIButtonTypeSystem? // Deprecated, use UIButtonTypeSystem instead

};

NS_CLASS_AVAILABLE_IOS(2_0) @interface UIButton : UIControl+ (instancetype)buttonWithType:(UIButtonType)buttonType;//創(chuàng)建button

@property(nonatomic)? ? ? ? ? UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero. On tvOS 10 or later, default is nonzero except for custom buttons.調(diào)整button整體內(nèi)部區(qū)域的位置和尺寸

@property(nonatomic)? ? ? ? ? UIEdgeInsets titleEdgeInsets;? ? ? ? ? ? ? ? // default is UIEdgeInsetsZero--調(diào)整button文字區(qū)域的位置和尺寸

@property(nonatomic)? ? ? ? ? BOOL? ? ? ? reversesTitleShadowWhenHighlighted; // default is NO. if YES, shadow reverses to shift between engrave and emboss appearance

@property(nonatomic)? ? ? ? ? UIEdgeInsets imageEdgeInsets;? ? ? ? ? ? ? ? // default is UIEdgeInsetsZero-----調(diào)整button圖片區(qū)域的位置和尺寸

@property(nonatomic)? ? ? ? ? BOOL? ? ? ? adjustsImageWhenHighlighted;? ? // default is YES. if YES, image is drawn darker when highlighted(pressed)

@property(nonatomic)? ? ? ? ? BOOL? ? ? ? adjustsImageWhenDisabled;? ? ? // default is YES. if YES, image is drawn lighter when disabled

@property(nonatomic)? ? ? ? ? BOOL? ? ? ? showsTouchWhenHighlighted __TVOS_PROHIBITED;? ? ? // default is NO. if YES, show a simple feedback (currently a glow) while highlighted

@property(null_resettable, nonatomic,strong)? UIColor? ? *tintColor NS_AVAILABLE_IOS(5_0); // The tintColor is inherited through the superview hierarchy. See UIView for more information.

@property(nonatomic,readonly) UIButtonType buttonType;

// you can set the image, title color, title shadow color, and background image to use for each state. you can specify data

// for a combined state by using the flags added together. in general, you should specify a value for the normal state to be used

// by other states which don't have a custom value set

- (void)setTitle:(nullable NSString *)title forState:(UIControlState)state;? ? ? ? ? ? ? ? ? ? // default is nil. title is assumed to be single line

- (void)setTitleColor:(nullable UIColor *)color forState:(UIControlState)state UI_APPEARANCE_SELECTOR; // default if nil. use opaque white

- (void)setTitleShadowColor:(nullable UIColor *)color forState:(UIControlState)state UI_APPEARANCE_SELECTOR; // default is nil. use 50% black

- (void)setImage:(nullable UIImage *)image forState:(UIControlState)state;? ? ? ? ? ? ? ? ? ? ? // default is nil. should be same size if different for different states

- (void)setBackgroundImage:(nullable UIImage *)image forState:(UIControlState)state UI_APPEARANCE_SELECTOR; // default is nil

- (void)setAttributedTitle:(nullable NSAttributedString *)title forState:(UIControlState)state NS_AVAILABLE_IOS(6_0); // default is nil. title is assumed to be single line

- (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);

// these are the values that will be used for the current state. you can also use these for overrides. a heuristic will be used to

// determine what image to choose based on the explict states set. For example, the 'normal' state value will be used for all states

// that don't have their own image defined.

@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

// return title and image views. will always create them if necessary. always returns nil for system buttons

@property(nullable, nonatomic,readonly,strong) UILabel? ? *titleLabel NS_AVAILABLE_IOS(3_0);

@property(nullable, nonatomic,readonly,strong) UIImageView *imageView? NS_AVAILABLE_IOS(3_0);

/ these return the rectangle for the background (assumes bounds), the content (image + title) and for the image and title separately. the content rect is calculated based

// on the title and image size and padding and then adjusted based on the control content alignment. there are no draw methods since the contents

// are rendered in separate subviews (UIImageView, UILabel)

- (CGRect)backgroundRectForBounds:(CGRect)bounds;

- (CGRect)contentRectForBounds:(CGRect)bounds;// 用來(lái)計(jì)算按鈕整體內(nèi)容區(qū)域的大小和位置

- (CGRect)titleRectForContentRect:(CGRect)contentRect;// 用來(lái)計(jì)算按鈕文字區(qū)域的大小和位置

- (CGRect)imageRectForContentRect:(CGRect)contentRect;// 用來(lái)計(jì)算按鈕圖片區(qū)域的大小和位置

@end

@interface UIButton(UIButtonDeprecated)

@property(nonatomic,strong) UIFont *font NS_DEPRECATED_IOS(2_0, 3_0) __TVOS_PROHIBITED;

@property(nonatomic) NSLineBreakMode lineBreakMode NS_DEPRECATED_IOS(2_0, 3_0) __TVOS_PROHIBITED;

@property(nonatomic) CGSize titleShadowOffset NS_DEPRECATED_IOS(2_0, 3_0) __TVOS_PROHIBITED;

@end#if TARGET_OS_IOS

@interface UIButton (SpringLoading)

@end

#endif

NS_ASSUME_NONNULL_END


注意:默認(rèn)情況下荚孵,Cocoa Touch 框架中的UIButton只支持左圖右文的布局方式坯临,而且還不能直接設(shè)置圖文間距典徘。


但是在現(xiàn)實(shí)開發(fā)中颁督,我們會(huì)遇到要求--上圖片下文字菊霜;右圖左文欲诺;上文下圖的情況狱庇。

針對(duì)這種情況,我們的通常思路就是創(chuàng)建UIButton的子類或者類別

UIButton的類別


#import<UIKit/UIKit.h>

//系統(tǒng)默認(rèn)的布局是內(nèi)容整體居中舀透,圖片在左栓票,文字在右,圖片和文字間距為 0愕够。

typedef NS_ENUM(NSInteger,ZBButtonLayoutStyle) {

ZBButtonLayoutTitleLeft,

ZBButtonLayoutTitleRight,

ZBButtonLayoutTitleTop,

ZBButtonLayoutTitleBottom,

};

@interface UIButton (TitleAndImageLayout)

- (void)zb_setLayoutStyle:(ZBButtonLayoutStyle)style spacing:(CGFloat)spacing;

@end


#import "UIButton+TitleAndImageLayout.h"

@implementation UIButton (TitleAndImageLayout)

- (void)zb_setLayoutStyle:(ZBButtonLayoutStyle)style spacing:(CGFloat)spacing{

[self layoutIfNeeded];//為了獲取最新的 imageView 和 titleLabel 的 frame走贪,強(qiáng)制更新

CGRect titleFrame = self.titleLabel.frame;

CGRect imageFrame = self.imageView.frame;

switch (style) {

//? UIEdgeInsets 類型有四個(gè)成員變量 top、left惑芭、bottom坠狡、right,分別表示上左下右四個(gè)方向的偏移量遂跟,正值代表往內(nèi)縮進(jìn)逃沿,也就是往按鈕中心靠攏,負(fù)值代表往外擴(kuò)張幻锁,就是往按鈕邊緣貼近凯亮。

case ZBButtonLayoutTitleLeft:

{

// 圖片右移

self.imageEdgeInsets = UIEdgeInsetsMake(0,

titleFrame.size.width + spacing,

0,

-(titleFrame.size.width + spacing));

// 文字左移

self.titleEdgeInsets = UIEdgeInsetsMake(0,

-(titleFrame.origin.x - imageFrame.origin.x),

0,

titleFrame.origin.x - imageFrame.origin.x);

}

break;

case ZBButtonLayoutTitleRight:

{

// 計(jì)算默認(rèn)的圖片文字間距

CGFloat originalSpacing = titleFrame.origin.x - (imageFrame.origin.x + imageFrame.size.width);

// 調(diào)整文字的位置

self.titleEdgeInsets = UIEdgeInsetsMake(0,

-(originalSpacing - spacing),

0,

(originalSpacing - spacing));

}

break;

case ZBButtonLayoutTitleTop:

{

// 圖片下移,右移

self.imageEdgeInsets = UIEdgeInsetsMake(titleFrame.size.height + spacing,

0,

0,

-(titleFrame.size.width));

// 文字上移越败,左移

self.titleEdgeInsets = UIEdgeInsetsMake(0,

-(imageFrame.size.width),

imageFrame.size.height + spacing,

0);

}

break;

case ZBButtonLayoutTitleBottom:

{

// 圖片上移触幼,右移

self.imageEdgeInsets = UIEdgeInsetsMake(0,

0,

titleFrame.size.height + spacing,

-(titleFrame.size.width));

// 文字下移,左移

self.titleEdgeInsets = UIEdgeInsetsMake(imageFrame.size.height + spacing,

-(imageFrame.size.width),

0,

0);

}

break;

default:

break;

}

}

@end

使用方法

//button的大小會(huì)自動(dòng)獲取圖片的大小究飞,字體大小默認(rèn)17

UIButton* left = [UIButton buttonWithType:UIButtonTypeCustom];

left.backgroundColor = [UIColor yellowColor];

[self.view addSubview:left];

left.frame = CGRectMake(50, 80, 50, 80);

[left setImage:[UIImage imageNamed:@"icon_交易方式@2x"] forState:UIControlStateNormal];

[left setTitle:@"左" forState:UIControlStateNormal];

left.titleLabel.font = [UIFont systemFontOfSize:36];

[left setTitleColor:[UIColor redColor] forState:UIControlStateNormal];

[left zb_setLayoutStyle:ZBButtonLayoutTitleLeft spacing:2];

創(chuàng)建UIButton的子類

#import<UIKit/UIKit.h>

typedef NS_ENUM(NSInteger,ZBButtonLayoutStyle) {

ZBButtonLayoutTitleLeft,

ZBButtonLayoutTitleRight,

ZBButtonLayoutTitleTop,

ZBButtonLayoutTitleBottom,

};

@interface UILayoutButton : UIButton

@property (assign,nonatomic)IBInspectable CGSize imageSize;//圖片大小

@property (nonatomic,assign)CGFloat titleAndImageSpace;//文字和圖片間的距離

@property (assign, nonatomic) ZBButtonLayoutStyle layoutStyle;? ? ///< 圖片和文字的相對(duì)位置

@end


--------------------

#import "UILayoutButton.h"

@implementation UILayoutButton

/*

// Only override drawRect: if you perform custom drawing.

// An empty implementation adversely affects performance during animation.

- (void)drawRect:(CGRect)rect {

// Drawing code

}

*/

- (void)setLayoutStyle:(ZBButtonLayoutStyle)layoutStyle{

_layoutStyle = layoutStyle;

if (layoutStyle!= ZBButtonLayoutTitleRight&&layoutStyle!= ZBButtonLayoutTitleLeft) {

self.titleLabel.textAlignment = NSTextAlignmentCenter;

}

}

#pragma mark---重寫父類方法置谦,改變title和image的坐標(biāo)

- (CGRect)imageRectForContentRect:(CGRect)contentRect{

if (self.layoutStyle == ZBButtonLayoutTitleLeft) {

CGFloat x = contentRect.size.width - self.titleAndImageSpace - self.imageSize.width ;

CGFloat y =? contentRect.size.height -? self.imageSize.height;

y = y/2;

CGRect rect = CGRectMake(x,y,self.imageSize.width,self.imageSize.height);

return rect;

} else if (self.layoutStyle == ZBButtonLayoutTitleBottom) {

CGFloat x =? contentRect.size.width -? self.imageSize.width;

CGFloat? y=? 0? ;

x = x / 2;

CGRect rect = CGRectMake(x,y,self.imageSize.width,self.imageSize.height);

return rect;

}else if (self.layoutStyle == ZBButtonLayoutTitleTop){

CGFloat x =? contentRect.size.width -? self.imageSize.width;

CGFloat? y=? contentRect.size.height-self.titleAndImageSpace-self.imageSize.height? ;

x = x / 2;

CGRect rect = CGRectMake(x,y,self.imageSize.width,self.imageSize.height);

return rect;

}

else {

return [super imageRectForContentRect:contentRect];

}

}

- (CGRect)titleRectForContentRect:(CGRect)contentRect {

if (self.layoutStyle == ZBButtonLayoutTitleLeft) {

return CGRectMake(0, 0, contentRect.size.width - self.titleAndImageSpace - self.imageSize.width , contentRect.size.height);

} else if (self.layoutStyle == ZBButtonLayoutTitleBottom) {

return CGRectMake(0,? self.titleAndImageSpace + self.imageSize.height , contentRect.size.width , contentRect.size.height - self.titleAndImageSpace - self.imageSize.height );

}

else if (self.layoutStyle == ZBButtonLayoutTitleTop){

return CGRectMake((contentRect.size.width- self.imageSize.width)/2.0 ,? 0 , contentRect.size.width , contentRect.size.height - self.titleAndImageSpace - self.imageSize.height );

}

else {

return [super titleRectForContentRect:contentRect];

}

}

@end

使用方法:


UILayoutButton *left = [UILayoutButton buttonWithType:UIButtonTypeCustom];

left.backgroundColor = [UIColor redColor];

left.titleLabel.backgroundColor = [UIColor grayColor];

left.imageView.backgroundColor = [UIColor purpleColor];

left.frame = CGRectMake(50, 160, 110, 30);

[left setTitle:@"標(biāo)題在左" forState:UIControlStateNormal];

left.imageSize = CGSizeMake(20, 20);//設(shè)置圖片大小

left.layoutStyle = ZBButtonLayoutTitleLeft;//布局風(fēng)格

[left setImage:[UIImage imageNamed:@"check_icon"] forState:UIControlStateNormal];

[self.view addSubview:left];

總結(jié):

以上方式都能實(shí)現(xiàn)重新布局UIButton的子控件的效果,各有優(yōu)缺點(diǎn):

各位堂鲤,可以把您的看法留在下方評(píng)論區(qū)。如有不足媒峡,也請(qǐng)指教瘟栖,我這里就抱磚引玉了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谅阿,一起剝皮案震驚了整個(gè)濱河市半哟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌签餐,老刑警劉巖寓涨,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異氯檐,居然都是意外死亡戒良,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門冠摄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)糯崎,“玉大人,你說(shuō)我怎么就攤上這事河泳∥帜兀” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拆挥,是天一觀的道長(zhǎng)薄霜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)竿刁,這世上最難降的妖魔是什么黄锤? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮食拜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘副编。我一直安慰自己负甸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布痹届。 她就那樣靜靜地躺著呻待,像睡著了一般。 火紅的嫁衣襯著肌膚如雪队腐。 梳的紋絲不亂的頭發(fā)上蚕捉,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音柴淘,去河邊找鬼迫淹。 笑死秘通,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的敛熬。 我是一名探鬼主播肺稀,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼应民!你這毒婦竟也來(lái)了话原?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诲锹,失蹤者是張志新(化名)和其女友劉穎繁仁,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體归园,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黄虱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔓倍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悬钳。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖偶翅,靈堂內(nèi)的尸體忽然破棺而出默勾,到底是詐尸還是另有隱情,我是刑警寧澤聚谁,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布母剥,位于F島的核電站,受9級(jí)特大地震影響形导,放射性物質(zhì)發(fā)生泄漏环疼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一朵耕、第九天 我趴在偏房一處隱蔽的房頂上張望炫隶。 院中可真熱鬧,春花似錦阎曹、人聲如沸伪阶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)栅贴。三九已至,卻和暖如春熏迹,著一層夾襖步出監(jiān)牢的瞬間檐薯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工注暗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坛缕,地道東北人墓猎。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像祷膳,于是被迫代替她去往敵國(guó)和親陶衅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容