UIButton: 如何使用 imageEdgeInsets 和 titleEdgeInsets 将图像和文本居中?

如果我只在一个按钮中放入一个图像,然后将 image EdgeInsets 设置得更靠近顶部,图像就会保持居中,所有的工作都如预期的那样:

[button setImage:image forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, 0.0)];

如果我只在按钮中放入一个文本,并将 titleEdgeInsets 设置得更靠近底部,那么文本将保持居中位置,并且所有工作都如预期的那样:

[button setTitle:title forState:UIControlStateNormal];
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, -30, 0.0)];

但是,如果我把4行放在一起,文本会干扰图像,两者都会失去中心对齐。

我所有的图片都有30个像素宽度,如果我在 setTitleEdgeInsets 的 UIEdgeInsetMake 的左参数中放置30个像素宽度,那么文本将再次居中。问题是图像从来不会居中,因为它似乎依赖于 button.titleLabel 大小。我已经尝试了许多计算按钮大小,图像大小,title 标签大小,从来没有得到完美的居中。

有人已经有同样的问题了吗?

135293 次浏览

找到方法了。

首先,配置 titleLabel的文本(因为样式,例如,粗体,斜体等)。然后,根据图片的宽度使用 setTitleEdgeInsets:

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:10.0]];


// Left inset is the negative of image width.
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, -image.size.width, -25.0, 0.0)];

然后,考虑到文本边界的宽度,使用 setTitleEdgeInsets:

[button setImage:image forState:UIControlStateNormal];


// Right inset is the negative of text bounds width.
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, -button.titleLabel.bounds.size.width)];

现在图像和文本将居中(在本例中,图像出现在文本上方)。

干杯。

无论如何,这里有一个通用的解决方案,可以让图像在文字上方居中,而不需要使用任何神奇的数字。返回文章页面

// the space between the image and text
CGFloat spacing = 6.0;


// lower the text and push it left so it appears centered
//  below the image
CGSize imageSize = button.imageView.frame.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);


// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = button.titleLabel.frame.size;
button.imageEdgeInsets = UIEdgeInsetsMake(
- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

下面的版本包含在下面的评论中建议的支持 IOS7 + 的更改。我自己还没有测试过这段代码,所以我不确定它的工作效果如何,或者如果在以前的 iOS 版本中使用它是否会崩溃。

// the space between the image and text
CGFloat spacing = 6.0;


// lower the text and push it left so it appears centered
//  below the image
CGSize imageSize = button.imageView.image.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);


// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}];
button.imageEdgeInsets = UIEdgeInsetsMake(
- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);


// increase the content height to avoid clipping
CGFloat edgeOffset = fabsf(titleSize.height - imageSize.height) / 2.0;
button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0);

Swift 5.0 版本

extension UIButton {
func alignVertical(spacing: CGFloat = 6.0) {
guard let imageSize = imageView?.image?.size,
let text = titleLabel?.text,
let font = titleLabel?.font
else { return }


titleEdgeInsets = UIEdgeInsets(
top: 0.0,
left: -imageSize.width,
bottom: -(imageSize.height + spacing),
right: 0.0
)


let titleSize = text.size(withAttributes: [.font: font])
imageEdgeInsets = UIEdgeInsets(
top: -(titleSize.height + spacing),
left: 0.0,
bottom: 0.0,
right: -titleSize.width
)


let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0
contentEdgeInsets = UIEdgeInsets(
top: edgeOffset,
left: 0.0,
bottom: edgeOffset,
right: 0.0
)
}
}

只要标签足够短,不会被截断,使用 button.titleLabel.frame.size.width就可以正常工作。但是,当标签文本被截断时,定位就不起作用了。拿走

CGSize titleSize = [[[button titleLabel] text] sizeWithFont:[[button titleLabel] font]];

即使标签文本被截断,对我也有效。

我看了现有的答案,但我也发现设置按钮框架是重要的第一步。

下面是我用来处理这个问题的函数:

const CGFloat kImageTopOffset   = -15;
const CGFloat kTextBottomOffset = -25;


+ (void) centerButtonImageTopAndTextBottom: (UIButton*)         button
frame: (CGRect)            buttonFrame
text: (NSString*)         textString
textColor: (UIColor*)          textColor
font: (UIFont*)           textFont
image: (UIImage*)          image
forState: (UIControlState)    buttonState
{
button.frame = buttonFrame;


[button setTitleColor: (UIColor*)       textColor
forState: (UIControlState) buttonState];


[button setTitle: (NSString*) textString
forState: (UIControlState) buttonState ];




[button.titleLabel setFont: (UIFont*) textFont ];


[button setTitleEdgeInsets: UIEdgeInsetsMake( 0.0, -image.size.width, kTextBottomOffset,  0.0)];


[button setImage: (UIImage*)       image
forState: (UIControlState) buttonState ];


[button setImageEdgeInsets: UIEdgeInsetsMake( kImageTopOffset, 0.0, 0.0,- button.titleLabel.bounds.size.width)];
}

这里有一些很好的例子,但是当处理多行文本(文本包装)时,我不能让它在所有情况下都工作。为了最终让它起作用,我结合了以下几个技巧:

  1. 我使用上面的 Jesse Crossen 例子,但是我固定了一个文本高度 我添加了指定水平文本边距的能力。 当允许文本换行时,边距非常有用,这样它就不会碰到 按钮的边缘:

    // the space between the image and text
    CGFloat spacing = 10.0;
    float   textMargin = 6;
    
    
    // get the size of the elements here for readability
    CGSize  imageSize   = picImage.size;
    CGSize  titleSize   = button.titleLabel.frame.size;
    CGFloat totalHeight = (imageSize.height + titleSize.height + spacing);      // get the height they will take up as a unit
    
    
    // lower the text and push it left to center it
    button.titleEdgeInsets = UIEdgeInsetsMake( 0.0, -imageSize.width +textMargin, - (totalHeight - titleSize.height), +textMargin );   // top, left, bottom, right
    
    
    // the text width might have changed (in case it was shortened before due to
    // lack of space and isn't anymore now), so we get the frame size again
    titleSize = button.titleLabel.bounds.size;
    
    
    button.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + spacing), 0.0, 0.0, -titleSize.width );     // top, left, bottom, right
    
  2. Make sure you setup the text label to wrap

    button.titleLabel.numberOfLines = 2;
    button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    button.titleLabel.textAlignment = UITextAlignmentCenter;
    
  3. 现在基本上可以了。然而,我有一些按钮不能正确渲染他们的图像。图像要么被移动到很远的右边,要么被移动到左边(它没有居中)。因此,我使用了一个 UIButton 布局覆盖技术来强制图像视图居中。

    @interface CategoryButton : UIButton
    @end
    
    
    @implementation CategoryButton
    
    
    - (void)layoutSubviews
    {
    // Allow default layout, then center imageView
    [super layoutSubviews];
    
    
    UIImageView *imageView = [self imageView];
    CGRect imageFrame = imageView.frame;
    imageFrame.origin.x = (int)((self.frame.size.width - imageFrame.size.width)/ 2);
    imageView.frame = imageFrame;
    }
    @end
    

不要反抗体制。如果你的布局变得太复杂以至于无法使用 Interface Builder + 或许一些简单的配置代码来管理,那么用一种更简单的方式使用 layoutSubviews来手动布局——这就是它的作用!其他的一切都会变成黑客行为。

创建一个 UIButton 子类并覆盖其 layoutSubviews方法,以编程方式对齐文本和图像。或者使用类似于 https://github.com/nickpaulson/BlockKit/blob/master/Source/UIView-BKAdditions.h的东西,这样您就可以使用块实现 layoutSubviews。

我为@TodCunningham 的回答制定了一个方法

 -(void) AlignTextAndImageOfButton:(UIButton *)button
{
CGFloat spacing = 2; // the amount of spacing to appear between image and title
button.imageView.backgroundColor=[UIColor clearColor];
button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
button.titleLabel.textAlignment = UITextAlignmentCenter;
// get the size of the elements here for readability
CGSize imageSize = button.imageView.frame.size;
CGSize titleSize = button.titleLabel.frame.size;


// lower the text and push it left to center it
button.titleEdgeInsets = UIEdgeInsetsMake(0.0, - imageSize.width, - (imageSize.height   + spacing), 0.0);


// the text width might have changed (in case it was shortened before due to
// lack of space and isn't anymore now), so we get the frame size again
titleSize = button.titleLabel.frame.size;


// raise the image and push it right to center it
button.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, -     titleSize.width);
}

或者你可以用这个分类:

@interface UIButton (VerticalLayout)


- (void)centerVerticallyWithPadding:(float)padding;
- (void)centerVertically;


@end




@implementation UIButton (VerticalLayout)


- (void)centerVerticallyWithPadding:(float)padding
{
CGSize imageSize = self.imageView.frame.size;
CGSize titleSize = self.titleLabel.frame.size;


CGFloat totalHeight = (imageSize.height + titleSize.height + padding);


self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height),
0.0f,
0.0f,
- titleSize.width);


self.titleEdgeInsets = UIEdgeInsetsMake(0.0f,
- imageSize.width,
- (totalHeight - titleSize.height),
0.0f);


}




- (void)centerVertically
{
const CGFloat kDefaultPadding = 6.0f;


[self centerVerticallyWithPadding:kDefaultPadding];
}




@end

假设你希望文本和图像都水平居中,图像在文本之上: 将文本置于 Interface Builder 的中心,并添加一个顶部插图(为图像腾出空间)。(左边的插图保留为0)。使用 Interface Builder 选择图像-它的实际位置将从代码设置,所以不要担心事情会看起来不好。与上面的其他答案不同,这实际上适用于所有当前支持的 ios 版本(5、6和7)。

在代码中,只需要在抓取图像后丢弃按钮的 ImageView (通过将按钮的图像设置为 null)(这也会自动将文本居中,如果需要的话可以进行包装)。然后用相同的帧大小和图像实例化您自己的 ImageView,并将其放置在中间。

这样你仍然可以从 Interface Builder 中选择图像(虽然它不会像在模拟器中那样在 iB 中对齐,但是其他的解决方案不能在所有支持的 ios 版本中兼容)

你可以使用这个 Swift 扩展,它部分基于 Jesse Crossen 的回答:

extension UIButton {
func centerLabelVerticallyWithPadding(spacing:CGFloat) {
// update positioning of image and title
let imageSize = self.imageView.frame.size
self.titleEdgeInsets = UIEdgeInsets(top:0,
left:-imageSize.width,
bottom:-(imageSize.height + spacing),
right:0)
let titleSize = self.titleLabel.frame.size
self.imageEdgeInsets = UIEdgeInsets(top:-(titleSize.height + spacing),
left:0,
bottom: 0,
right:-titleSize.width)


// reset contentInset, so intrinsicContentSize() is still accurate
let trueContentSize = CGRectUnion(self.titleLabel.frame, self.imageView.frame).size
let oldContentSize = self.intrinsicContentSize()
let heightDelta = trueContentSize.height - oldContentSize.height
let widthDelta = trueContentSize.width - oldContentSize.width
self.contentEdgeInsets = UIEdgeInsets(top:heightDelta/2.0,
left:widthDelta/2.0,
bottom:heightDelta/2.0,
right:widthDelta/2.0)
}
}

这定义了一个函数 centerLabelVerticallyWithPadding,用于适当地设置标题和图像插入。

它还设置 contentEdgeInsets,我认为这对于确保 intrinsicContentSize仍然正确工作是必要的,这需要使用 Auto Layout。

我相信所有子类 UIButton 的解决方案在技术上都是不合法的,因为您不应该子类 UIKit 控件。也就是说,理论上它们可能在未来的发行版中被打破。

我的用例使得 insets 难以管理:

  1. 按钮上的背景图像保持一致
  2. 在字符串长度和图像大小变化的地方,动态文本和图像发生变化

这就是我最后所做的,我很高兴:

  • 在故事板上创建一个带有背景图像的按钮(带有模糊和颜色的圆形)。

  • 在我的类中声明 UIImageView:

    @implementation BlahViewController {
    UIImageView *_imageView;
    }
    
  • Create image view instance on init:

    -(id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
    _imageView = [[UIImageView alloc] initWithCoder:aDecoder];
    }
    return self;
    }
    
  • In viewDidLoad add a new layer to the button for our image view and set text alignment:

    [self.btn addSubview:_imageView];
    [self.btn.titleLabel setTextAlignment:NSTextAlignmentCenter];
    
  • In the button click method add my chosen overlay image to the image view, size it to fit the image and center it in the button but move it up 15 so I can put the text offset below it:

    [_imageView setImage:[UIImage imageNamed:@"blahImageBlah]];
    [_imageView sizeToFit];
    _imageView.center = CGPointMake(ceilf(self.btn.bounds.size.width / 2.0f),
    ceilf((self.btn.bounds.size.height / 2.0f) - 15));
    [self.btn setTitle:@"Some new text" forState:UIControlStateNormal];
    

Note: ceilf() is important to ensure it's on a pixel boundary for image quality.

UIButton 子类

- (void)layoutSubviews {
[super layoutSubviews];
CGFloat spacing = 6.0;
CGSize imageSize = self.imageView.image.size;
CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(self.frame.size.width, self.frame.size.height - (imageSize.height + spacing))];
self.imageView.frame = CGRectMake((self.frame.size.width - imageSize.width)/2, (self.frame.size.height - (imageSize.height+spacing+titleSize.height))/2, imageSize.width, imageSize.height);
self.titleLabel.frame = CGRectMake((self.frame.size.width - titleSize.width)/2, CGRectGetMaxY(self.imageView.frame)+spacing, titleSize.width, titleSize.height);
}

我正在努力做到这一点,因为我不能得到我的视图的构造函数的图像大小和文本宽度。Jesse 的回答的两个小改动对我有效:

CGFloat spacing = 3;
self.titleEdgeInsets = UIEdgeInsetsMake(0.0, - image.size.width, - (image.size.height + spacing), 0.0);
CGSize titleSize = [name sizeWithAttributes:@{NSFontAttributeName:self.titleLabel.font}];
self.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

改变是:

  • 使用 [NSString sizeWithAttributes]得到文本宽度;
  • 直接在 UIImage而不是 UIImageView上获取图像大小

杰西 · 克罗森的回答只有一个小小的改动,让它完美地适合我:

而不是:

CGSize titleSize = button.titleLabel.frame.size;

我用过这个:

CGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName:button.titleLabel.font}];

为 Xcode 11 + 更新

在我最初的答案中描述的插入已经在 Xcode 的最新版本中移到了大小检查器中。我不是100% 清楚什么时候切换发生,但读者应该检查大小检查器,如果插入信息没有在属性检查器中找到。下面是新插入屏幕的一个示例(位于大小属性检查器的顶部,截至11.5)。

insets_moved_to_size_inspector

原始答案

其他答案没有错,但是我只是想指出,在 Xcode 中使用零行代码可以直观地完成同样的行为。如果您不需要计算值,或者正在使用故事板/xib 构建(否则应用其他解决方案) ,则此解决方案非常有用。

注意-我确实理解 OP 的问题是一个需要代码的问题。我只是为了完整性提供这个答案,并作为那些使用故事板/xibs 的人的一个合乎逻辑的替代方案。

要使用边缘插入修改按钮的图像、标题和内容视图的间距,您可以选择按钮/控件并打开属性检查器。向下滚动到检查器的中间,找到 Edge 插图的部分。

edge-insets

还可以访问和修改标题、图像或内容视图的特定边缘插入。

menu-options

编辑: 为 Swift 3更新

如果你正在寻找一个关于 Jesse Crossen 的答案的 Swift 解决方案,你可以把它添加到 UIButton 的一个子类中:

override func layoutSubviews() {


let spacing: CGFloat = 6.0


// lower the text and push it left so it appears centered
//  below the image
var titleEdgeInsets = UIEdgeInsets.zero
if let image = self.imageView?.image {
titleEdgeInsets.left = -image.size.width
titleEdgeInsets.bottom = -(image.size.height + spacing)
}
self.titleEdgeInsets = titleEdgeInsets


// raise the image and push it right so it appears centered
//  above the text
var imageEdgeInsets = UIEdgeInsets.zero
if let text = self.titleLabel?.text, let font = self.titleLabel?.font {
let attributes = [NSFontAttributeName: font]
let titleSize = text.size(attributes: attributes)
imageEdgeInsets.top = -(titleSize.height + spacing)
imageEdgeInsets.right = -titleSize.width
}
self.imageEdgeInsets = imageEdgeInsets


super.layoutSubviews()
}

这对我来说很有用,有几个按钮,不同的图像宽度和不同的标题长度:

UIButton子类

override func layoutSubviews() {
super.layoutSubviews()


if let image = imageView?.image {


let margin = 30 - image.size.width / 2
let titleRect = titleRectForContentRect(bounds)
let titleOffset = (bounds.width - titleRect.width - image.size.width - margin) / 2




contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
imageEdgeInsets = UIEdgeInsetsMake(0, margin, 0, 0)
titleEdgeInsets = UIEdgeInsetsMake(0, (bounds.width - titleRect.width -  image.size.width - margin) / 2, 0, 0)
}


}

工作良好的按钮大小80x80像素。

[self.leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, 10.0, 20.0, 10.0)];
[self.leftButton setTitleEdgeInsets:UIEdgeInsetsMake(60, -75.0, 0.0, 0.0)];

我做了一些调整,使图像在中心水平对齐:

// the space between the image and text
let spacing = CGFloat(36.0);


// lower the text and push it left so it appears centered
//  below the image
let imageSize = tutorialButton.imageView!.frame.size;
tutorialButton.titleEdgeInsets = UIEdgeInsetsMake(
0, -CGFloat(imageSize.width), -CGFloat(imageSize.height + spacing), 0.0);


// raise the image and push it right so it appears centered
//  above the text
let titleSize = tutorialButton.titleLabel!.frame.size;
tutorialButton.imageEdgeInsets = UIEdgeInsetsMake(
-CGFloat(titleSize.height + spacing), CGFloat((tutorialButton.frame.width - imageSize.width) / 2), 0.0, -CGFloat(titleSize.width));

使用这段代码,您将得到类似于下面这样的内容title and image alignment

extension UIButton {
func alignTextUnderImage() {
guard let imageView = imageView else {
return
}
self.contentVerticalAlignment = .Top
self.contentHorizontalAlignment = .Center
let imageLeftOffset = (CGRectGetWidth(self.bounds) - CGRectGetWidth(imageView.bounds)) / 2//put image in center
let titleTopOffset = CGRectGetHeight(imageView.bounds) + 5
self.imageEdgeInsets = UIEdgeInsetsMake(0, imageLeftOffset, 0, 0)
self.titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset, -CGRectGetWidth(imageView.bounds), 0, 0)
}
}

是否必须使用边缘插入? 如果不是,您可以尝试定位相对于中心父视图

extension UIButton
{
func centerImageAndTextVerticaAlignment(spacing: CGFloat)
{
var titlePoint : CGPoint = convertPoint(center, fromView:superview)
var imageViewPoint : CGPoint = convertPoint(center, fromView:superview)
titlePoint.y += ((titleLabel?.size.height)! + spacing)/2
imageViewPoint.y -= ((imageView?.size.height)! + spacing)/2
titleLabel?.center = titlePoint
imageView?.center = imageViewPoint


}
}

使用 Swift 3 + 语法的 UIButton 扩展:

extension UIButton {
func alignImageAndTitleVertically(padding: CGFloat = 6.0) {
let imageSize: CGSize = imageView!.image!.size
titleEdgeInsets = UIEdgeInsetsMake(0.0, -imageSize.width, -(imageSize.height + padding), 0.0)
let labelString = NSString(string: titleLabel!.text!)
let titleSize = labelString.size(attributes: [NSFontAttributeName: titleLabel!.font])
self.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + padding), 0.0, 0.0, -titleSize.width)
let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
self.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0)
}
}

原答案: https://stackoverflow.com/a/7199529/3659227

您需要按照文本的宽度将图像向右移动。然后按照图像的宽度将文本向左移动。

UIEdgeInsets imageEdgeInsets = self.remoteCommandsButtonLights.imageEdgeInsets;
imageEdgeInsets.left = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:[button.titleLabel font]}].width;
imageEdgeInsets.bottom = 14.0;
button.imageEdgeInsets = imageEdgeInsets;


UIEdgeInsets titleEdgeInsets = self.remoteCommandsButtonLights.titleEdgeInsets;
titleEdgeInsets.left = -button.currentImage.size.width;
titleEdgeInsets.top = 20.0;
button.titleEdgeInsets = titleEdgeInsets;

然后调整顶部和底部插图以调整 Y 轴。这也可以通过编程来完成,但是对于您的图像大小应该是恒定的。而 X 轴的插入将需要根据每个按钮中文本标签的大小进行更改。

Swift 4杰西 · 克罗森(Jesse Crossen)最新答案:

extension UIButton {
func alignVertical(spacing: CGFloat = 6.0) {
guard let imageSize = self.imageView?.image?.size,
let text = self.titleLabel?.text,
let font = self.titleLabel?.font
else { return }
self.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0.0)
let labelString = NSString(string: text)
let titleSize = labelString.size(withAttributes: [kCTFontAttributeName as NSAttributedStringKey: font])
self.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
self.contentEdgeInsets = UIEdgeInsets(top: edgeOffset, left: 0.0, bottom: edgeOffset, right: 0.0)
}
}

这样使用:

override func viewDidLayoutSubviews() {
button.alignVertical()
}

将此代码添加到扩展名 Swift 4.2中

 func moveImageLeftTextCenter(imagePadding: CGFloat = 30.0){
guard let imageViewWidth = self.imageView?.frame.width else{return}
guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
self.contentHorizontalAlignment = .left
imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imagePadding - imageViewWidth / 2, bottom: 0.0, right: 0.0)
titleEdgeInsets = UIEdgeInsets(top: 0.0, left: (bounds.width - titleLabelWidth) / 2 - imageViewWidth, bottom: 0.0, right: 0.0)
}
func moveImageRIghtTextCenter(imagePadding: CGFloat = 30.0){
guard let imageViewWidth = self.imageView?.frame.width else{return}
guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
self.contentHorizontalAlignment = .right
imageEdgeInsets = UIEdgeInsets(top: 0.0, left:0.0 , bottom: 0.0, right: imagePadding - imageViewWidth / 2)
titleEdgeInsets = UIEdgeInsets(top: 0.0, left:0.0 , bottom: 0.0, right:(bounds.width - titleLabelWidth) / 2 - imageViewWidth)
}

我想说的是,这个方法对我很有效:

extension UIButton {
public func centerImageAndTextVertically(spacing: CGFloat) {
layoutIfNeeded()
let contentFrame = contentRect(forBounds: bounds)
let imageFrame = imageRect(forContentRect: contentFrame)
let imageLeftInset = bounds.size.width * 0.5 - imageFrame.size.width * 0.5
let imageTopInset = -(imageFrame.size.height + spacing * 0.5)
let titleFrame = titleRect(forContentRect: contentFrame)
let titleLeftInset = ((bounds.size.width - titleFrame.size.width) * 0.5) - imageFrame.size.width
let titleTopInmset = titleFrame.size.height + spacing * 0.5
imageEdgeInsets = UIEdgeInsets(top: imageTopInset, left: imageLeftInset, bottom: 0, right: 0)
titleEdgeInsets = UIEdgeInsets(top: titleTopInmset, left: titleLeftInset, bottom: 0, right: 0)
}
}