iOS---UIButton詳解及如何調整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;//創建button

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

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

@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-----調整button圖片區域的位置和尺寸

@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;// 用來計算按鈕整體內容區域的大小和位置

- (CGRect)titleRectForContentRect:(CGRect)contentRect;// 用來計算按鈕文字區域的大小和位置

- (CGRect)imageRectForContentRect:(CGRect)contentRect;// 用來計算按鈕圖片區域的大小和位置

@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


注意:默認情況下,Cocoa Touch 框架中的UIButton只支持左圖右文的布局方式,而且還不能直接設置圖文間距。


但是在現實開發中,我們會遇到要求--上圖片下文字;右圖左文;上文下圖的情況。

針對這種情況,我們的通常思路就是創建UIButton的子類或者類別

UIButton的類別


#import<UIKit/UIKit.h>

//系統默認的布局是內容整體居中,圖片在左,文字在右,圖片和文字間距為 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,強制更新

CGRect titleFrame = self.titleLabel.frame;

CGRect imageFrame = self.imageView.frame;

switch (style) {

//? UIEdgeInsets 類型有四個成員變量 top、left、bottom、right,分別表示上左下右四個方向的偏移量,正值代表往內縮進,也就是往按鈕中心靠攏,負值代表往外擴張,就是往按鈕邊緣貼近。

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:

{

// 計算默認的圖片文字間距

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

// 調整文字的位置

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的大小會自動獲取圖片的大小,字體大小默認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];

創建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;? ? ///< 圖片和文字的相對位置

@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的坐標

- (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:@"標題在左" forState:UIControlStateNormal];

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

left.layoutStyle = ZBButtonLayoutTitleLeft;//布局風格

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

[self.view addSubview:left];

總結:

以上方式都能實現重新布局UIButton的子控件的效果,各有優缺點:

各位,可以把您的看法留在下方評論區。如有不足,也請指教,我這里就抱磚引玉了。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容