@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的子控件的效果,各有優缺點:
各位,可以把您的看法留在下方評論區。如有不足,也請指教,我這里就抱磚引玉了。