将UIButton上的文本和图像与imageEdgeInsets和titleEdgeInsets对齐

时间:2010-12-30 17:09:29

标签: iphone ios uibutton uikit

我想在两行文字左侧放置一个图标,使图像与文本开头之间的空间大约为2-3像素。控件本身是水平居中对齐的(通过Interface Builder设置)

按钮类似于以下内容:

|                  |
|[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: how to center an image and a text using imageEdgeInsets and titleEdgeInsets?

16 个答案:

答案 0 :(得分:358)

我同意imageEdgeInsetstitleEdgeInsets上的文档应该更好,但我想出了如何在不诉诸反复试验的情况下获得正确的定位。

一般的想法出现在this question,但那就是你想要文本和图像居中。我们不希望图像和文本单独居中,我们希望图像和文本作为单个实体集中在一起。这实际上是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];

当然你可能想要为此做一个很好的方法,可能会添加第二种方法,这是留给读者的练习。

答案 1 :(得分:356)

我参加这个派对有点晚了,但我觉得我有一些有用的东西要加上。

Kekoa的答案很棒但是,正如RonLugge所提到的,它可以使按钮不再尊重sizeToFit,或者更重要的是,可以使按钮在内在大小时剪切其内容。糟糕!

首先,

关于我如何相信imageEdgeInsetstitleEdgeInsets工作的简要说明:

docs for 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.

噢,是的!我忘了,the docs警告过我。他们在一定程度上说:

  

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

一个可以提供帮助的属性,而且contentEdgeInsetsThe docs就此而言,部分:

  

该按钮使用此属性来确定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

你得到了什么?

Spacing and frame are now correct.

看起来像是我的赢家。


在斯威夫特工作并且根本不想做任何想法?这是Swift中扩展的最终版本:

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        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)
    }
}

答案 2 :(得分:37)

在界面生成器中。选择UIButton - &gt;属性检查器 - &gt; Edge =标题并修改边缘插入

答案 3 :(得分:33)

此外,如果你想做类似于

的事情

enter image description here

你需要

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

enter image description here

  1. 找到所有必需的值并设置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)];
    
  2. 这将在按钮上排列您的标题和图像。

    另请注意在每次重播时更新此内容

    夫特

    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)
                }
            }
        }
    }
    

答案 4 :(得分:27)

使用此功能可以避免很多麻烦 -

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

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

斯威夫特3:

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

答案 5 :(得分:20)

Xcode 8.0 中,您只需在尺寸检查器中更改insets即可。

选择UIButton - &gt;属性检查器 - &gt;转到大小检查器并修改内容,图像和标题插入。

enter image description here

如果您想更改右侧的图像,只需在属性检查器中将语义属性更改为Force Right-to-left

enter image description here

答案 6 :(得分:18)

我对这个派对来说有点晚了,但我想我有一些有用的东西可以补充: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. 使用&#34; center&#34;,&#34; top&#34;,&#34; bottom&#34;,&#34; left&#34;调整可布局属性或&#34;对&#34; button attributes
  4. 此处代码(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()
        }
    }
    

答案 7 :(得分: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)
    }
}

答案 8 :(得分:6)

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)

答案 9 :(得分:1)

以下是如何使用imageEdgeInsets的简单示例 这将产生一个30x30的按钮,其可击中区域一直大于10像素(50x50)

    var expandHittableAreaAmt : CGFloat = 10
    var buttonWidth : CGFloat = 30
    var button = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
    button.frame = CGRectMake(0, 0, buttonWidth+expandHittableAreaAmt, buttonWidth+expandHittableAreaAmt)
    button.imageEdgeInsets = UIEdgeInsetsMake(expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt)
    button.setImage(UIImage(named: "buttonImage"), forState: .Normal)
    button.addTarget(self, action: "didTouchButton:", forControlEvents:.TouchUpInside)

答案 10 :(得分:1)

我写下面的代码。在产品版本中效果很好。 Supprot Swift 4.2 +

extension UIButton{
 enum ImageTitleRelativeLocation {
    case imageUpTitleDown
    case imageDownTitleUp
    case imageLeftTitleRight
    case imageRightTitleLeft
}
 func centerContentRelativeLocation(_ relativeLocation: 
                                      ImageTitleRelativeLocation,
                                   spacing: CGFloat = 0) {
    assert(contentVerticalAlignment == .center,
           "only works with contentVerticalAlignment = .center !!!")

    guard (title(for: .normal) != nil) || (attributedTitle(for: .normal) != nil) else {
        assert(false, "TITLE IS NIL! SET TITTLE FIRST!")
        return
    }

    guard let imageSize = self.currentImage?.size else {
        assert(false, "IMGAGE IS NIL! SET IMAGE FIRST!!!")
        return
    }
    guard let titleSize = titleLabel?
        .systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) else {
            assert(false, "TITLELABEL IS NIL!")
            return
    }

    let horizontalResistent: CGFloat
    // extend contenArea in case of title is shrink
    if frame.width < titleSize.width + imageSize.width {
        horizontalResistent = titleSize.width + imageSize.width - frame.width
        print("horizontalResistent", horizontalResistent)
    } else {
        horizontalResistent = 0
    }

    var adjustImageEdgeInsets: UIEdgeInsets = .zero
    var adjustTitleEdgeInsets: UIEdgeInsets = .zero
    var adjustContentEdgeInsets: UIEdgeInsets = .zero

    let verticalImageAbsOffset = abs((titleSize.height + spacing) / 2)
    let verticalTitleAbsOffset = abs((imageSize.height + spacing) / 2)

    switch relativeLocation {
    case .imageUpTitleDown:

        adjustImageEdgeInsets.top = -verticalImageAbsOffset
        adjustImageEdgeInsets.bottom = verticalImageAbsOffset
        adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
        adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2

        adjustTitleEdgeInsets.top = verticalTitleAbsOffset
        adjustTitleEdgeInsets.bottom = -verticalTitleAbsOffset
        adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
        adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2

        adjustContentEdgeInsets.top = spacing
        adjustContentEdgeInsets.bottom = spacing
        adjustContentEdgeInsets.left = -horizontalResistent
        adjustContentEdgeInsets.right = -horizontalResistent
    case .imageDownTitleUp:
        adjustImageEdgeInsets.top = verticalImageAbsOffset
        adjustImageEdgeInsets.bottom = -verticalImageAbsOffset
        adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
        adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2

        adjustTitleEdgeInsets.top = -verticalTitleAbsOffset
        adjustTitleEdgeInsets.bottom = verticalTitleAbsOffset
        adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
        adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2

        adjustContentEdgeInsets.top = spacing
        adjustContentEdgeInsets.bottom = spacing
        adjustContentEdgeInsets.left = -horizontalResistent
        adjustContentEdgeInsets.right = -horizontalResistent
    case .imageLeftTitleRight:
        adjustImageEdgeInsets.left = -spacing / 2
        adjustImageEdgeInsets.right = spacing / 2

        adjustTitleEdgeInsets.left = spacing / 2
        adjustTitleEdgeInsets.right = -spacing / 2

        adjustContentEdgeInsets.left = spacing
        adjustContentEdgeInsets.right = spacing
    case .imageRightTitleLeft:
        adjustImageEdgeInsets.left = titleSize.width + spacing / 2
        adjustImageEdgeInsets.right = -titleSize.width - spacing / 2

        adjustTitleEdgeInsets.left = -imageSize.width - spacing / 2
        adjustTitleEdgeInsets.right = imageSize.width + spacing / 2

        adjustContentEdgeInsets.left = spacing
        adjustContentEdgeInsets.right = spacing
    }

    imageEdgeInsets = adjustImageEdgeInsets
    titleEdgeInsets = adjustTitleEdgeInsets
    contentEdgeInsets = adjustContentEdgeInsets

    setNeedsLayout()
}
}

答案 11 :(得分:0)

Swift 3中的优雅方式,更好地理解:

serial = function(x,y,z){
  table_serial <- data.frame()
  for (i in 1:4 ) {
       s1 <- serial.test(VAR(cbind(x,y), p=i, type="const"), lags.pt=4, type=z)$serial$statistic[[1]]
       s2 <- serial.test(VAR(cbind(x,y), p=i, type="const"), lags.pt=4, type=z)$serial$p.value[[1]]
       table_serial <- rbind(table_serial, c(i, s1, s2))
   }
   colnames(table_serial) <- c("Lag", "Chi", "p")
   table_serial
}

# test it
set.seed(1234)  # make it reproducible
serial(rnorm(100), rnorm(100), "BG")
  Lag      Chi         p
1   1 13.76826 0.8420485
2   2 27.77865 0.1147436
3   3 17.09634 0.6467093
4   4 13.58514 0.8508920

答案 12 :(得分:0)

在 swift 5.3 和 @ravron 的启发下回答:

extension UIButton {
    /// Fits the image and text content with a given spacing
    /// - Parameters:
    ///   - spacing: Spacing between the Image and the text
    ///   - contentXInset: The spacing between the view to the left image and the right text to the view
    func setHorizontalMargins(imageTextSpacing: CGFloat, contentXInset: CGFloat = 0) {
        let imageTextSpacing = imageTextSpacing / 2
        
        contentEdgeInsets = UIEdgeInsets(top: 0, left: (imageTextSpacing + contentXInset), bottom: 0, right: (imageTextSpacing + contentXInset))
        imageEdgeInsets = UIEdgeInsets(top: 0, left: -imageTextSpacing, bottom: 0, right: imageTextSpacing)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: imageTextSpacing, bottom: 0, right: -imageTextSpacing)
    }
}

它从视图到图像以及从标签到视图添加了额外的水平边距

答案 13 :(得分:0)

我的垂直居中方法:

extension UIButton {
    
    /// Layout image and title with vertical centering.
    /// - Parameters:
    ///   - size: The button size.
    ///   - imageTopOffset: Top offset for image.
    ///   - spacing: Distance between image and title.
    func verticalAlignmentByCenter(size: CGSize, imageTopOffset: CGFloat, spacing: CGFloat) {
        let contentRect = contentRect(forBounds: CGRect(origin: .zero, size: size))
        let imageRect = imageRect(forContentRect: contentRect)
        let titleRect = titleRect(forContentRect: contentRect)

        let imageTop = imageTopOffset - imageRect.origin.y
        let imageLeft = contentRect.width/2 - imageRect.width/2
        imageEdgeInsets = UIEdgeInsets(top: imageTop, left: imageLeft, bottom: 0, right: 0)

        let titleTop = imageTopOffset + spacing + imageRect.height - titleRect.origin.y
        let titleLeft = titleRect.origin.x - contentRect.width/2 - titleRect.width/2
        titleEdgeInsets = UIEdgeInsets(top: titleTop, left: titleLeft, bottom: 0, right: 0)
    }
    
}

答案 14 :(得分:0)

@ravron 在提供这个答案方面做得非常出色。

就我而言,我不仅需要在图像和标题之间添加水平宽度,还需要在按钮的“前导”和“尾随”中添加水平空间。

因此,我使用了内部图像和标签的内在内容大小:

<块引用>

接收视图的自然大小,仅考虑视图本身的属性。

|                                                                                   |
|[LEADING SPACE] [Image] [SPACE BETWEEN IMAGE AND TITLE] Add To     [TRAILING SPACE]|
|                                                        Favorites      |

let leadingTrailingSpace = 10
let horizontalWidthBetweenImageAndTitle = 4
let insetAmount = horizontalWidthBetweenImageAndTitle / CGFloat(2)
    button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -CGFloat(insetAmount), bottom: 0, right: insetAmount);
    button.titleEdgeInsets = UIEdgeInsets(top: 0, left: CGFloat(insetAmount), bottom: 0, right: -insetAmount);
    button.contentEdgeInsets = UIEdgeInsets(top: 0, left: CGFloat(insetAmount), bottom: 0, right: insetAmount);
    
    let buttonWidth =
        (button.titleLabel?.intrinsicContentSize.width ?? 0) +
        (button.imageView?.intrinsicContentSize.width ?? 0)
        + insetAmount
        + leadingTrailingSpace
    button.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true

答案 15 :(得分:-1)

解决方案的快速4.2版本如下:

let spacing: CGFloat = 10 // the amount of spacing to appear between image and title
self.button?.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: spacing)
self.button?.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing, bottom: 0, right: 0)