iOS UIButton 设置图片文字垂直排列

在实际的iOS项目开发中,我们经常需要改变系统的控件的样式,自己定义一个,同样的当我们发现系统自带的某些方法不好使时,我们也会想到重写这个方法。 本文主要记录笔者设置UIButton图片文字垂直排列的方法,最终解决了在图片和文字垂直排列的情况下,如果文字长度变化会导致图片位置变动的问题,对 于此问题网上有比较多的做法,我就不多说了,在此记录这点细节仅为加深印象并方便以后查阅。如有纰漏还请见谅

方案一:通过调整按钮图片和文字的内边距

UIEdgeInsets

typedef struct UIEdgeInsets {
    CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
} UIEdgeInsets;

在UIButton中有三个对EdgeInsets的设置:ContentEdgeInsets、titleEdgeInsets、imageEdgeInsets

@property(nonatomic)          UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero
@property(nonatomic)          UIEdgeInsets titleEdgeInsets;                // default is UIEdgeInsetsZero
@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

UIEdgeInsetsMake

里面的四个参数表示距离上边界、左边界、下边界、右边界的距离,默认都为零,title/image在button的正中央

UIKIT_STATIC_INLINE UIEdgeInsets UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right) {
    UIEdgeInsets insets = {top, left, bottom, right};
    return insets;
}
@interface UIButton (UIButtonExt)  
- (void)centerImageAndTitle:(float)space;  
- (void)centerImageAndTitle;  
@end  
 
@implementation UIButton (UIButtonExt)  
- (void)centerImageAndTitle:(float)spacing  
{      
    // get the size of the elements here for readability  
    CGSize imageSize = self.imageView.frame.size;  
    CGSize titleSize = self.titleLabel.frame.size;  
 
    // get the height they will take up as a unit  
    CGFloat totalHeight = (imageSize.height + titleSize.height + spacing);  
 
    // raise the image and push it right to center it  
    self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height), 0.0, 0.0, - titleSize.width);  
 
    // lower the text and push it left to center it  
    self.titleEdgeInsets = UIEdgeInsetsMake(0.0, - imageSize.width, - (totalHeight - titleSize.height),0.0);      
}  
 
- (void)centerImageAndTitle  
{  
    const int DEFAULT_SPACING = 6.0f;  
    [self centerImageAndTitle:DEFAULT_SPACING];  
 }  
@end
后面经过测试,如果button的文字长度变更,会导致图片位置变化,经过多次修改UIEdgeInsets的值也没有达到期望效果,最终我们采用下述方案:自定义按钮继承系统的UIButton,重写layoutSubviews方法,布局子控件,调整按钮内imageView的Center和titleLabel的Frame解决上述问题。 
方案二

-(void)layoutSubviews {
    [super layoutSubviews];
 
    // Center image
    CGPoint center = self.imageView.center;
    center.x = self.frame.size.width/2;
    center.y = self.imageView.frame.size.height/2;
    self.imageView.center = center;
 
    //Center text
    CGRect newFrame = [self titleLabel].frame;
    newFrame.origin.x = 0;
    newFrame.origin.y = self.imageView.frame.size.height + 5;
    newFrame.size.width = self.frame.size.width;
 
    self.titleLabel.frame = newFrame;
    self.titleLabel.textAlignment = UITextAlignmentCenter;
}

这里笔者采取方案二示例如下:

#import "BSQuickLoginButton.h"

@implementation BSQuickLoginButton

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    //调整图片(imageView)的位置和尺寸
    CGPoint center = self.imageView.center;
    center.x = self.frame.size.width/2;
    center.y = self.imageView.frame.size.height/2;
    self.imageView.center = center;
    
    
    //调整文字(titleLable)的位置和尺寸
   CGRect newFrame = self.titleLabel.frame;
    newFrame.origin.x = 0;
    newFrame.origin.y = self.imageView.frame.size.height;
    
    newFrame.size.width = self.frame.size.width;
    newFrame.size.height = self.frame.size.height - self.imageView.frame.size.height;
    
    self.titleLabel.frame = newFrame;
    
    
   //让文字居中
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
}
@end

   这里值得注意的一个小细节是:允许直接修改对象的结构体属性,但不能直接修改对象的结构体属性的成员,所以这里我们不能直接拿到按钮的frame属性的赋值设置,需要先设置一个临时的tempFrame,然后在赋值给按钮的frame.

如图所示:会提示表达式不可被指定不可分配的错误

另外,开发中我们经常会写self.imageView.frame.size.height一类繁琐的重复的代码,这里我们可以采取一种偷懒的小技巧:
给控件(UIView)写一个分类 如下:
#import "UIView+Extension.h"

@implementation UIView (Extension)

- (void)setX:(CGFloat)x
{
    CGRect frame = self.frame;
    frame.origin.x = x;
    self.frame = frame;
}

- (CGFloat)x
{
    return self.frame.origin.x;
}

- (void)setY:(CGFloat)y
{
    CGRect frame = self.frame;
    frame.origin.y = y;
    self.frame = frame;
}

- (CGFloat)y
{
    return self.frame.origin.y;
}

- (void)setWidth:(CGFloat)width
{
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}

- (CGFloat)width
{
    return self.frame.size.width;
}

- (void)setHeight:(CGFloat)height
{
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame = frame;
}

- (CGFloat)height
{
    return self.frame.size.height;
}

- (void)setCenterX:(CGFloat)centerX
{
    CGPoint center = self.center;
    center.x = centerX;
    self.center = center;
}

- (CGFloat)centerX
{
    return self.center.x;
}

- (void)setCenterY:(CGFloat)centerY
{
    CGPoint center = self.center;
    center.y = centerY;
    self.center = center;
}

- (CGFloat)centerY
{
    return self.center.y;
}

@end

与此同时,重写了frame的各属性的set、get方法,将不再受上述不能直接赋值的细节问题影响,上述方案代码亦可简化如下:

- (void)awakeFromNib
{
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    // 调整图片的位置和尺寸
    self.imageView.y = 0;
    self.imageView.centerX = self.width * 0.5;
    
    // 调整文字的位置和尺寸
    self.titleLabel.x = 0;
    self.titleLabel.y = self.imageView.height;
    self.titleLabel.width = self.width;
    self.titleLabel.height = self.height - self.titleLabel.y;
}

在项目实战中,笔者通过自定义按钮,实现了如下登录界面中快速登录按钮图片和文字垂直排列的样式需求,效果如下

对 比:

 
 
 
 
原文地址:https://www.cnblogs.com/mysticCoder/p/4799778.html