使用imageEdgeInsets和titleEdgeInsets来对齐UIButton上的文本和图像。

281
历史问题。请注意,15年后,.imagePadding是图像和标签之间的间距。

enter image description here


原始问题:

我想在两行文本的左侧放置一个图标,使图像与文本的开头之间有大约2-3像素的间距。控件本身在水平方向上是居中对齐的(通过界面构建器设置)。

按钮将类似于以下内容:

|                  |
|[Image] Add To    |
|        Favorites |

我试图使用contentEdgeInset、imageEdgeInsets和titleEdgeInsets进行配置,但没有成功。我知道负值会扩大边缘,而正值会缩小边缘以将其移动到中心位置。
[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];

但是这样显示不正确。我一直在调整数值,但是从左插入值从-5到-10的变化似乎没有按预期的方式移动它。-10会将文本全部移动到左侧,所以我期望-5会将其从左侧移动到一半,但实际上并没有。
插入值的逻辑是什么?我对图像放置和相关术语不太熟悉。
我使用了这个SO问题作为参考,但是我的数值似乎有些问题。 UIButton:如何使用imageEdgeInsets和titleEdgeInsets居中图像和文本?
21个回答

461

虽然我来晚了,但我认为我有一些有用的东西要补充。

Kekoa的答案很好,但正如RonLugge所提到的那样,这可能会使按钮不再尊重sizeToFit,或者更重要的是,当按钮具有内在大小时,可能导致按钮截断其内容。哎呀!

不过,首先需要简要解释一下我认为imageEdgeInsetstitleEdgeInsets的工作原理:

有关imageEdgeInsets的文档部分地表示:

使用此属性可以调整按钮图像的有效绘制矩形的大小和位置。您可以为每个四个插图(上、左、下、右)指定不同的值。正值会缩小或缩进该边缘-将其移动到按钮的中心。负值会扩展或突出该边缘。

我认为编写此文档时想象的是按钮没有标题,只有一个图像。以这种方式考虑更加合理,并且行为方式与UIEdgeInsets通常相同。基本上,对于正插图,图像的框架(或具有titleEdgeInsets的标题)向内移动,而对于负插图,则向外移动。

好的,那么怎样?

我来了!以下是默认设置的图像和标题(按钮边框为绿色,只是为了显示其位置):

Starting image; no space between title and image.

当您想要在图像和标题之间留出间距,而不会使它们中的任何一个被压缩时,您需要设置四个不同的插图,其中两个应用于图像和标题各自。这是因为您不希望更改这些元素框架的大小,而只是它们的位置。当您开始以这种方式思考时,需要对Kekoa的优秀类进行所需更改。

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
}

@end

等等,你说,当我这样做时,我得到了这个:

Spacing is good, but the image and title are outside the view's frame.

哦,对了!我忘了,文档警告了我。其中一部分内容如下:

此属性仅用于在布局期间定位图像。按钮不使用此属性确定intrinsicContentSizesizeThatFits:

但是确实有一个属性可以帮助我们,那就是contentEdgeInsets该文档中提到的其中一部分内容如下:

按钮使用此属性确定intrinsicContentSizesizeThatFits:

听起来不错。因此,让我们再次调整类别:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
    self.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
}

@end

那你得到了什么?

间距和框架现在是正确的。

对我来说看起来像个赢家。


正在使用Swift工作,不想进行任何思考吗?这是Swift扩展的最终版本:

extension UIButton {

    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let isRTL = UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft
        if isRTL {
           imageEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
           titleEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
           contentEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: -insetAmount)
        } else {
           imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
           titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
           contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
        }
    }
}

29
太棒了!虽然晚了几年才加入,但这解决了intrinsicContentSize不正确的问题。在这些自动布局的日子里,这非常重要,因为原来的答案已经被接受了。 - Acey
2
如果您希望在按钮的外部和图像、标签之间保持相同的间距,则需要将spacing添加到self.contentEdgeInsets的四个值中,如下所示:self.contentEdgeInsets = UIEdgeInsetsMake(spacing, spacing + insetAmount, spacing, spacing + insetAmount); - Erik van der Neut
1
很棒的答案,可惜当图像右对齐且文本长度可变时,它的效果并不是很好。 - jlpiedrahita
2
几乎完美的答案!唯一缺少的是当它在从右到左的界面上运行时,图像和标题的插入应该被反转。 - jeeeyul
1
@YestayMuratov 设置 button.imageView?.contentMode = .scaleAspectFit。我为此制作了一个小测试应用程序,您可以在其中进行操作 https://github.com/tomas789/UIButtonEdgeInsets - tomas789
显示剩余7条评论

421

我同意imageEdgeInsetstitleEdgeInsets的文档应该更好,但我找到了一种方法来正确定位它们而不必进行试错。

总体思路在这个问题中提到,但那是如果你想要文本和图像同时居中的情况。我们不希望图像和文本分别居中,而是希望将图像和文本作为单个实体一起居中。事实上,这正是UIButton已经做到的,因此我们只需要调整间距即可。

CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);

我还将其转换为UIButton的一个类别,以便于使用:

UIButton+Position.h

@interface UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;

@end

UIButton+Position.m

@implementation UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
    self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}

@end

那么现在我所需要做的就是:

[button centerButtonAndImageWithSpacing:10];

每次我都能得到我想要的东西。 不再手动处理边缘插图。

编辑:交换图像和文本

响应评论中的@Javal

使用相同的机制,我们可以交换图像和文本。 要完成交换,只需使用负间距,但还要包括文本和图像的宽度。这将需要已知框架并执行布局。

[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];

当然您可能想要为此编写一个好的方法,可能还想添加第二个类别的方法,这留给读者自己练习。


6
如何修复[button sizeToFit]以使其正确调整大小? - RonLugge
@RonLugge,我知道我晚了好几年,但请查看我的答案以修复sizeToFit - ravron
非常感谢。这对我很有帮助。但是我认为如果我们使用第一个解决方法,最好添加btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft。 - ShineWang
当我在 IB 中尝试使用它时,它对我不起作用。 - pronebird
@Andy,我认为没有任何迹象表明在IB中查看时应该起作用。 - Kekoa
显示剩余7条评论

43

如果你想要制作类似于

enter image description here

的东西,你需要:

1.将按钮设置为水平和垂直对齐方式

enter image description here

  1. Find all required values and set UIImageEdgeInsets

            CGSize buttonSize = button.frame.size;
            NSString *buttonTitle = button.titleLabel.text;
            CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }];
            UIImage *buttonImage = button.imageView.image;
            CGSize buttonImageSize = buttonImage.size;
    
            CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text
    
            [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText,
                                                        (buttonSize.width - buttonImageSize.width) / 2,
                                                        0,0)];                
            [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText,
                                                        titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width  +  (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width,
                                                        0,0)];
    

这将在按钮上排列您的标题和图像。

另外,请注意每次重新布局时更新此内容。


Swift

import UIKit

extension UIButton {
    // MARK: - UIButton+Aligment

    func alignContentVerticallyByCenter(offset:CGFloat = 10) {
        let buttonSize = frame.size

        if let titleLabel = titleLabel,
            let imageView = imageView {

            if let buttonTitle = titleLabel.text,
                let image = imageView.image {
                let titleString:NSString = NSString(string: buttonTitle)
                let titleSize = titleString.sizeWithAttributes([
                    NSFontAttributeName : titleLabel.font
                    ])
                let buttonImageSize = image.size

                let topImageOffset = (buttonSize.height - (titleSize.height + buttonImageSize.height + offset)) / 2
                let leftImageOffset = (buttonSize.width - buttonImageSize.width) / 2
                imageEdgeInsets = UIEdgeInsetsMake(topImageOffset,
                                                   leftImageOffset,
                                                   0,0)

                let titleTopOffset = topImageOffset + offset + buttonImageSize.height
                let leftTitleOffset = (buttonSize.width - titleSize.width) / 2 - image.size.width

                titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset,
                                                   leftTitleOffset,
                                                   0,0)
            }
        }
    }
}

39

在接口生成器中选择UIButton -> 属性检查器 -> 边缘=标题并修改边距


32

Xcode 8.0中,您可以通过更改大小检查器中的insets来轻松完成。

选择UIButton -> 属性检查器 -> 转到大小检查器并修改内容、图像和标题插图。

输入图片描述

如果你想要在右侧更改图像,你可以在属性检查器中将语义属性更改为Force Right-to-left

输入图片描述


在我的情况下,使用Xcode 10按钮图像从未移动到文本的右侧。你能帮忙吗? - Satish Mavani
嗨Satish,这也可以在xcode 10上正常工作。希望您设置的是图像而不是背景图像,并且您还可以使用大小检查器更改图像缩放比例。 - Sahil
这个答案对我很有帮助。请注意,如果您想支持RTL和LTR,您需要在代码中进行操作-您需要为所有情况切换右侧和左侧的值。但是,至少如果您使用此答案,您可以在Interface Builder中查看布局。之后,您需要编写匹配的代码。 - Andy Weinstein
是的,安迪。如果我们要支持RTL和LTR,我们必须通过代码来实现。但是,如果我们只是改变插图,那么我们可以使用Storyboard来完成,否则就必须通过编程来实现。 - Sahil

31

通过使用这个,你可以避免很多麻烦 --

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;

这将自动将您的所有内容对齐到左侧(或您想要的任何位置)

Swift 3:

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;

myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center; //修正了打字错误 - Naishta

20

虽然我来晚了一点,但我认为我有一些有用的东西可以补充 :o)。

我创建了一个UIButton子类,其目的是能够选择按钮图像的布局位置,可以是垂直或水平。

这意味着您可以制作这种类型的按钮:different kind of buttons

以下是使用我的类创建这些按钮的详细信息:

func makeButton (imageVerticalAlignment:LayoutableButton.VerticalAlignment, imageHorizontalAlignment:LayoutableButton.HorizontalAlignment, title:String) -> LayoutableButton {
    let button = LayoutableButton ()

    button.imageVerticalAlignment = imageVerticalAlignment
    button.imageHorizontalAlignment = imageHorizontalAlignment

    button.setTitle(title, for: .normal)

    // add image, border, ...

    return button
}

let button1 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .left, title: "button1")
let button2 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .right, title: "button2")
let button3 = makeButton(imageVerticalAlignment: .top, imageHorizontalAlignment: .center, title: "button3")
let button4 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button4")
let button5 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button5")
button5.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

为此,我添加了2个属性:imageVerticalAlignmentimageHorizontalAlignment。当然,如果您的按钮只有图像或标题...根本不使用此类!

我还添加了一个名为imageToTitleSpacing的属性,它允许您调整标题和图像之间的间距。

这个类尽力与新的布局属性直接或组合使用imageEdgeInsetstitleEdgeInsetscontentEdgeInsets时保持兼容。

正如@ravron所解释的那样,我尽力使按钮内容边缘正确(如您可以看到的红色边框)。

您还可以在Interface Builder中使用它:

  1. 创建UIButton
  2. 更改按钮类别
  3. 使用“中心”、“顶部”、“底部”、“左侧”或“右侧”的布局属性进行调整button attributes

这是代码(gist):

@IBDesignable
class LayoutableButton: UIButton {

    enum VerticalAlignment : String {
        case center, top, bottom, unset
    }


    enum HorizontalAlignment : String {
        case center, left, right, unset
    }


    @IBInspectable
    var imageToTitleSpacing: CGFloat = 8.0 {
        didSet {
            setNeedsLayout()
        }
    }


    var imageVerticalAlignment: VerticalAlignment = .unset {
        didSet {
            setNeedsLayout()
        }
    }

    var imageHorizontalAlignment: HorizontalAlignment = .unset {
        didSet {
            setNeedsLayout()
        }
    }

    @available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageVerticalAlignment' instead.")
    @IBInspectable
    var imageVerticalAlignmentName: String {
        get {
            return imageVerticalAlignment.rawValue
        }
        set {
            if let value = VerticalAlignment(rawValue: newValue) {
                imageVerticalAlignment = value
            } else {
                imageVerticalAlignment = .unset
            }
        }
    }

    @available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageHorizontalAlignment' instead.")
    @IBInspectable
    var imageHorizontalAlignmentName: String {
        get {
            return imageHorizontalAlignment.rawValue
        }
        set {
            if let value = HorizontalAlignment(rawValue: newValue) {
                imageHorizontalAlignment = value
            } else {
                imageHorizontalAlignment = .unset
            }
        }
    }

    var extraContentEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var contentEdgeInsets: UIEdgeInsets {
        get {
            return super.contentEdgeInsets
        }
        set {
            super.contentEdgeInsets = newValue
            self.extraContentEdgeInsets = newValue
        }
    }

    var extraImageEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var imageEdgeInsets: UIEdgeInsets {
        get {
            return super.imageEdgeInsets
        }
        set {
            super.imageEdgeInsets = newValue
            self.extraImageEdgeInsets = newValue
        }
    }

    var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var titleEdgeInsets: UIEdgeInsets {
        get {
            return super.titleEdgeInsets
        }
        set {
            super.titleEdgeInsets = newValue
            self.extraTitleEdgeInsets = newValue
        }
    }

    //Needed to avoid IB crash during autolayout
    override init(frame: CGRect) {
        super.init(frame: frame)
    }


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.imageEdgeInsets = super.imageEdgeInsets
        self.titleEdgeInsets = super.titleEdgeInsets
        self.contentEdgeInsets = super.contentEdgeInsets
    }

    override func layoutSubviews() {
        if let imageSize = self.imageView?.image?.size,
            let font = self.titleLabel?.font,
            let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) {

            var _imageEdgeInsets = UIEdgeInsets.zero
            var _titleEdgeInsets = UIEdgeInsets.zero
            var _contentEdgeInsets = UIEdgeInsets.zero

            let halfImageToTitleSpacing = imageToTitleSpacing / 2.0

            switch imageVerticalAlignment {
            case .bottom:
                _imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
                _imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
                _titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
                _titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
            case .top:
                _imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
                _imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
                _titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
                _titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
                _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
            case .center:
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
                break
            case .unset:
                break
            }

            switch imageHorizontalAlignment {
            case .left:
                _imageEdgeInsets.left = -halfImageToTitleSpacing
                _imageEdgeInsets.right = halfImageToTitleSpacing
                _titleEdgeInsets.left = halfImageToTitleSpacing
                _titleEdgeInsets.right = -halfImageToTitleSpacing
                _contentEdgeInsets.left = halfImageToTitleSpacing
                _contentEdgeInsets.right = halfImageToTitleSpacing
            case .right:
                _imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
                _imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
                _titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
                _titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
                _contentEdgeInsets.left = halfImageToTitleSpacing
                _contentEdgeInsets.right = halfImageToTitleSpacing
            case .center:
                _imageEdgeInsets.left = textSize.width / 2.0
                _imageEdgeInsets.right = -textSize.width / 2.0
                _titleEdgeInsets.left = -imageSize.width / 2.0
                _titleEdgeInsets.right = imageSize.width / 2.0
                _contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
                _contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
            case .unset:
                break
            }

            _contentEdgeInsets.top += extraContentEdgeInsets.top
            _contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
            _contentEdgeInsets.left += extraContentEdgeInsets.left
            _contentEdgeInsets.right += extraContentEdgeInsets.right

            _imageEdgeInsets.top += extraImageEdgeInsets.top
            _imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
            _imageEdgeInsets.left += extraImageEdgeInsets.left
            _imageEdgeInsets.right += extraImageEdgeInsets.right

            _titleEdgeInsets.top += extraTitleEdgeInsets.top
            _titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
            _titleEdgeInsets.left += extraTitleEdgeInsets.left
            _titleEdgeInsets.right += extraTitleEdgeInsets.right

            super.imageEdgeInsets = _imageEdgeInsets
            super.titleEdgeInsets = _titleEdgeInsets
            super.contentEdgeInsets = _contentEdgeInsets

        } else {
            super.imageEdgeInsets = extraImageEdgeInsets
            super.titleEdgeInsets = extraTitleEdgeInsets
            super.contentEdgeInsets = extraContentEdgeInsets
        }

        super.layoutSubviews()
    }
}

1
我修复了一些东西,以避免出现“错误:IB Designables:无法更新自动布局状态:代理崩溃”的问题。https://gist.github.com/nebiros/ecf69ff9cb90568edde071386c6c4ddb - nebiros
@nebiros,你能解释一下出了什么问题以及你是如何修复它的吗?谢谢。 - gbitaudeau
@gbitaudeau 当我复制并粘贴脚本时,我遇到了这个错误:error: IB Designables: Failed to update auto layout status: The agent crashed,因为没有重写 init(frame: CGRect) 方法,同时我添加了 @available 注释……如果你想的话,可以使用 diff -Naur 命令进行比较。;-) - nebiros
有一个小的修复(针对非常长的标题),建议使用 titleLabel?.frame.width 而不是 textSize.width ;) - Konstantin

14

Swift 4.x

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let writingDirection = UIApplication.shared.userInterfaceLayoutDirection
        let factor: CGFloat = writingDirection == .leftToRight ? 1 : -1

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
        self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

使用方法:

button.centerTextAndImage(spacing: 10.0)

如何使用自定义图像尺寸? - midhun p

12

我会根据更新后的 Xcode 13 来更新答案。

关于图像和文本对齐,我们不必使用任何扩展或单行代码。Xcode 在属性选项卡中提供了预定义属性,如下图所示。

定位属性有 4 个图像属性 -顶部,底部,前导和尾随

XCode 13 属性选项卡


1
该配置仅适用于IOS 15及更高版本,请查看我的答案以实现向后兼容性 https://dev59.com/rW855IYBdhLWcg3wrGdY#70138193 - Oscar Emilio Perez Martinez
布局和填充是我在我的 XCode -> 版本 14.1 中看不到的选项。 - jose920405

9
Riley Avron的回答中有一个小补充,针对账户区域设置的更改:
extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let writingDirection = UIApplication.sharedApplication().userInterfaceLayoutDirection
        let factor: CGFloat = writingDirection == .LeftToRight ? 1 : -1

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
        self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接