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的子控件的效果,各有优缺点:

各位,可以把您的看法留在下方评论区。如有不足,也请指教,我这里就抱砖引玉了。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容