UIButton的默认显示样式是图片居左,文字居右,如下图1:
但是有时候我们根据需求需要调整按钮中图片和标题的位置,最常见的就是图片居上,文字居下显示的按钮,如下图2所示:
实现这种居中显示的图上文下的按钮方式有很多,比如最简单的方法:自定义View,上面放一个UIButton一个UILabel子控件。
这里我们介绍其他方法来实现UIButton图片和标题的位置调整:
- 一种是通过类别(Category)调整位置;
- 一种是通过继承重写系统方法调整位置。
通过类别(Category)调整位置
通过类别的方法修改图片标题的位置主要是用了UIButton的两个位置属性:titleEdgeInsets
,imageEdgeInsets
。通过修改按钮中image
和title
的edgeInsets
来改变相对位置。
@property(nonatomic) UIEdgeInsets titleEdgeInsets; // default is UIEdgeInsetsZero
@property(nonatomic) UIEdgeInsets imageEdgeInsets; // default is UIEdgeInsetsZero
UIEdgeInsets有四个参数:top, left, bottom, right,
分别代表上左下右的偏移量。
top
: 为正数的时候,是往下偏移,为负数的时候往上偏移;
left
: 为正数的时候往右偏移,为负数的时候往左偏移;
bottom
: 为正数的时候往上偏移,为负数的时候往下偏移;
right
:为正数的时候往左偏移,为负数的时候往右偏移;
修改按钮中image和title位置的关键就是正确的设置这两个属性值的参数,网上很多介绍的方法里写的都是固定参数,如果每次使用都要去计算的话那就太麻烦了,这里我们通过获取image和title的size来设定偏移量,实现方法的通用。这也是创建一个UIButton的category的原因,方便以后的复用。
下面贴上category的代码,其中计算titleEdgeInsets
和imageEdgeInsets
的代码是最核心的地方,具体的计算思路可以从代码里看出来,就不文字介绍了。这里的计算思路是最关键的地方,只要知道怎么计算,就可以使用UIButton实现其他图文效果,而不止是图上文下的居中效果。
#import <UIKit/UIKit.h>
@interface UIButton (ZXCenterButton)
/**
图片居上,文字居下,图文居中按钮
@param spaceBetween image和label之间的间距,若设为nil则距离为0
@param fontSize 标题字体大小,若设为nil则为默认字体大小17
*/
-(instancetype)initCenterBtnWithFrame:(CGRect)frame
spaceBetween:(NSNumber*)spaceBetween
imageNamed:(NSString *)imageName
title:(NSString *)title
fontSize:(NSNumber*)fontSize;
@end
#import "UIButton+ZXCenterButton.h"
@implementation UIButton (ZXCenterButton)
-(instancetype)initCenterBtnWithFrame:(CGRect)frame spaceBetween:(NSNumber*)spaceBetween imageNamed:(NSString *)imageName title:(NSString *)title fontSize:(NSNumber*)fontSize{
if (self = [super initWithFrame:frame]) {
CGFloat font = fontSize == nil ? 17 : [fontSize floatValue];
[self setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
[self setTitle:title forState:UIControlStateNormal];
self.titleLabel.font = [UIFont systemFontOfSize:font];
// 图片的宽高
CGFloat imageW = self.imageView.frame.size.width;
CGFloat imageH = self.imageView.frame.size.height;
// 计算标题的size
CGSize titleSize = [self string:title sizeWithFont:[UIFont systemFontOfSize:font]];
// 图片+标题的总宽高
CGFloat totalW = imageW + titleSize.width;
CGFloat totalH = imageH + titleSize.height + spaceBetween.floatValue;
// 设置按钮图片偏移
[self setImageEdgeInsets:UIEdgeInsetsMake(-(totalH/2 - imageH/2), totalW/2 - imageW/2, (totalH/2 - imageH/2), -(totalW/2 - imageW/2))];
// 设置按钮标题偏移
[self setTitleEdgeInsets:UIEdgeInsetsMake((totalH/2 - titleSize.height/2), -(totalW/2 - titleSize.width/2), -(totalH/2 - titleSize.height/2), totalW/2 - titleSize.width/2)];
}
return self;
}
// 根据文字的长度、字体 来计算size
- (CGSize)string:(NSString *)string sizeWithFont:(UIFont *)font{
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSFontAttributeName] = font;
CGSize maxSize = CGSizeMake(MAXFLOAT, MAXFLOAT);
return [string boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}
@end
这种方法使用的时候注意Button的宽度设置和title的string长度,如果按钮宽度太小,标题的string太长,title无法全部显示时,label的宽度计算会出现偏差造成布局不居中。所以使用的时候要确保title能完全显示。
通过继承调整位置
通过继承的方法调整image和label的位置其实也有两种实现方法:
- 一种是在
- (void)layoutSubviews
里面重写self.titleLabel.frame
和self.imageView.frame
的rect值;
- 另一种就是本文要介绍的,重写系统方法改变title和image的布局。
通过继承需要重写的两个系统方法是:
Objective-C
- (CGRect)titleRectForContentRect:(CGRect)contentRect;
- (CGRect)imageRectForContentRect:(CGRect)contentRect;
具体实现方法直接见代码:
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
CGRect titleRect = CGRectMake(0, CGRectGetHeight(self.bounds)/3 * 2, CGRectGetWidth(self.bounds),CGRectGetHeight(self.bounds)/3);
return titleRect;
}
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
CGFloat width = CGRectGetWidth(self.bounds);
// 图片占按钮高度的2/3
CGRect imageRect = CGRectMake(0, 0, width, CGRectGetHeight(self.bounds)/3 * 2);
return imageRect;
}
使用这种方法的时候记得按钮的标题需要设置为居中,此方法来自我朋友的一篇文章,详情请移步,谢谢。
总结
解决问题的方法有各种各样,重要的是能解决问题,每个人的偏好都不一样。本文介绍的两种方法,第一种通过类别修改位置需要对UIEdgeInsets
属性理解透彻而且需要有很好的图形位置想象能力,否则自己很容易搞晕,但是类别的好处是以后直接拿来用就可以,不用再创建类复制粘贴了;第二种计算就相对来说比较简单了,但是需要创建类来继承,复制粘贴代码。大家选择适合自己的就好。