wake-up-neo.net

Ausrichten von Text und Bild auf UIButton mit imageEdgeInsets und titleEdgeInsets

Ich möchte ein Symbol links von den zwei Textzeilen platzieren, so dass zwischen Bild und Textanfang etwa 2-3 Pixel Abstand sind. Das Steuerelement selbst ist horizontal zentriert (durch Interface Builder festgelegt).

Der Button würde ungefähr so ​​aussehen:

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

Ich versuche, dies mit contentEdgeInset, imageEdgeInsets und titleEdgeInsets ohne Erfolg zu konfigurieren. Ich verstehe, dass ein negativer Wert den Rand erweitert, während ein positiver Wert ihn verkleinert, um ihn näher an die Mitte zu bewegen.

Ich habe es versucht:

[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];

dies wird jedoch nicht richtig angezeigt. Ich habe die Werte angepasst, aber von -5 auf -10 auf der linken Einfügung zu gehen, scheint ihn nicht in der erwarteten Weise zu verschieben. -10 scootet den Text ganz nach links, also habe ich erwartet, dass -5 auf halben Weg von der linken Seite abrutscht, aber es funktioniert nicht. 

Was ist die Logik hinter den Einsätzen? Ich bin mit Bildplatzierungen und verwandten Begriffen nicht vertraut.

Ich habe diese SO - Frage als Referenz verwendet, aber etwas über meine Werte ist nicht richtig . UIButton: Wie zentriere ich ein Bild und einen Text mit imageEdgeInsets und titleEdgeInsets?

224
Justin Galzic

Ich stimme zu, dass die Dokumentation zu imageEdgeInsets und titleEdgeInsets besser sein sollte, aber ich habe herausgefunden, wie man die richtige Positionierung erhält, ohne auf Versuch und Irrtum zurückzugreifen.

Die allgemeine Idee ist hier bei diese Frage , aber das war, wenn Sie Text und Bild zentriert haben wollten. Wir möchten nicht, dass das Bild und der Text einzeln zentriert werden. Wir möchten, dass das Bild und der Text als eine einzige Einheit zentriert werden. Dies ist in der Tat auch das, was UIButton bereits tut, also müssen wir nur den Abstand anpassen.

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

Ich habe dies auch in eine Kategorie für UIButton umgewandelt, so dass es einfach zu bedienen ist:

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

Jetzt muss ich nur noch:

[button centerButtonAndImageWithSpacing:10];

Und ich bekomme jedes Mal was ich brauche. Man muss nicht mehr manuell mit den Edge-Inserts arbeiten.

EDIT: Bild und Text vertauschen

Als Antwort auf @Javal in Kommentaren

Mit diesem Mechanismus können wir das Bild und den Text vertauschen. Um den Swap durchzuführen, verwenden Sie einfach einen negativen Abstand, schließen Sie aber auch die Breite des Textes und des Bildes ein. Dies erfordert, dass Frames bekannt sind und das Layout bereits ausgeführt wird.

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

Natürlich möchten Sie wahrscheinlich eine Nizza-Methode dafür erstellen und möglicherweise eine zweite Kategorie-Methode hinzufügen, die dem Leser als Übung überlassen wird.

351
Kekoa

Ich bin ein bisschen spät zu dieser Party, aber ich glaube, ich habe etwas Nützliches hinzuzufügen. 

Kekoas Antwort ist großartig, aber, wie RonLugge erwähnt, kann die Schaltfläche sizeToFit nicht mehr respektieren oder, was noch wichtiger ist, bewirkt, dass die Schaltfläche ihren Inhalt abschneidet, wenn sie intrinsisch groß ist. Yikes!

Zuerst aber 

Eine kurze Erklärung, wie ich glaube, dass imageEdgeInsets und titleEdgeInsets funktionieren:

Die docs für imageEdgeInsets haben zum Teil folgendes zu sagen:

Verwenden Sie diese Eigenschaft, um das effektive Zeichnungsrechteck für das Schaltflächenbild zu skalieren und neu zu positionieren. Sie können für jeden der vier Einsätze einen anderen Wert angeben (oben, links, unten, rechts). Ein positiver Wert verkleinert oder setzt diese Kante ein und bewegt sie näher an die Mitte der Schaltfläche. Ein negativer Wert erweitert oder verkürzt diesen Rand.

Ich glaube, dass in dieser Dokumentation geschrieben wurde, dass der Button keinen Titel hat, nur ein Bild. Es macht viel mehr Sinn auf diese Weise zu denken und verhält sich wie UIEdgeInsets normalerweise. Grundsätzlich wird der Rahmen des Bildes (oder der Titel mit titleEdgeInsets) für positive Einfügungen nach innen und für negative Einfügungen nach außen verschoben. 

In Ordnung und jetzt?

Ich komme dahin! Standardmäßig haben Sie ein Bild und einen Titel (der Schaltflächenrahmen ist grün, um anzuzeigen, wo er sich befindet): 

Starting image; no space between title and image.

Wenn Sie einen Abstand zwischen einem Bild und einem Titel haben möchten, ohne dass dabei ein Quetschen verursacht wird, müssen Sie vier verschiedene Einfügungen festlegen, und zwar jeweils zwei für Bild und Titel. Das liegt daran, dass Sie nicht die Größen der Frames dieser Elemente ändern möchten, sondern nur deren Positionen. Wenn Sie anfangen, auf diese Weise zu denken, wird die erforderliche Änderung der hervorragenden Kategorie von Kekoa klar:

@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

Aber warte, sagst du, wenn ich das tue, bekomme ich das)

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

Oh ja! Ich habe vergessen, die Dokumente habe mich davor gewarnt. Sie sagen zum Teil:

Diese Eigenschaft wird nur zum Positionieren des Bildes während des Layouts verwendet. Die Schaltfläche verwendet diese Eigenschaft nicht, um intrinsicContentSize und sizeThatFits: zu bestimmen.

Aber is eine Eigenschaft, die helfen kann, und das ist contentEdgeInsets. Die Dokumente zum Teil sagen:

Die Schaltfläche verwendet diese Eigenschaft, um intrinsicContentSize und sizeThatFits: zu bestimmen.

Das klingt gut. Lassen Sie uns die Kategorie noch einmal verbessern:

@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

Und was bekommst du?

Spacing and frame are now correct.

Sieht für mich wie ein Gewinner aus. 


Arbeiten in Swift und möchten gar nicht nachdenken? Hier ist die endgültige Version der Erweiterung in 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)
    }
}
338
ravron

Im Interface Builder. Wählen Sie den UIButton -> Attribute Inspector -> Edge = Title und ändern Sie die Edge-Einsätze

37
Freeman

Auch wenn Sie etwas ähnliches machen wollen 

enter image description here

Du brauchst

1.Stellen Sie die horizontale und vertikale Ausrichtung für die Schaltfläche auf

enter image description here

  1. Finde alle erforderlichen Werte und setze 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)];
    

Dadurch werden Titel und Bild auf der Schaltfläche angeordnet.

Bitte beachten Sie auch die Aktualisierung dieser Informationen bei jedem Relayout


Schnell

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

Sie können viele Probleme vermeiden, indem Sie diese verwenden -

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

Dadurch werden alle Inhalte automatisch nach links (oder wo immer Sie möchten) ausgerichtet.

Swift 3:

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

In Xcode 8.0 können Sie dies einfach tun, indem Sie insets im Größeninspektor ändern.

Wählen Sie UIButton -> Attributes Inspector -> gehen Sie zum Größeninspektor und ändern Sie den Inhalt, das Bild und den Titel.

 enter image description here

Wenn Sie das Bild auf der rechten Seite ändern möchten, können Sie die semantische Eigenschaft im Attribut-Inspektor einfach in Force Right-to-left ändern.

 enter image description here

20
Sahil

Ich bin auch etwas spät dran bei dieser Party, aber ich glaube, ich habe etwas Nützliches hinzuzufügen: o).

Ich habe eine UIButton-Unterklasse erstellt, deren Zweck darin besteht, wählen zu können, wo das Bild der Schaltfläche vertikal oder horizontal angeordnet ist.

Es bedeutet, dass Sie diese Art von Schaltflächen erstellen können:  different kind of buttons

Hier die Details zum Erstellen dieser Schaltflächen mit meiner Klasse:

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)

Dazu habe ich zwei Attribute hinzugefügt: imageVerticalAlignment und imageHorizontalAlignment. Natürlich, wenn Ihre Schaltfläche nur ein Bild oder einen Titel hat ... verwenden Sie diese Klasse überhaupt nicht!

Ich habe auch ein Attribut namens imageToTitleSpacing hinzugefügt, mit dem Sie den Abstand zwischen Titel und Bild anpassen können.

Diese Klasse versucht möglichst gut kompatibel zu sein, wenn Sie imageEdgeInsets, titleEdgeInsets und contentEdgeInsets direkt oder in Kombination mit den neuen Layoutattributen verwenden möchten.

Wie @ravron uns erklärt, bemühe ich mich, den Rand der Schaltfläche korrekt zu machen (wie Sie mit den roten Rändern sehen können).

Sie können es auch im Interface Builder verwenden: 

  1. Erstellen Sie einen UIButton
  2. Ändern Sie die Button-Klasse
  3. Anpassen der layoutfähigen Attribute mit "center", "top", "bottom", "left" oder "right"  button attributes

Hier der Code ( 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()
    }
}
16
gbitaudeau

Eine kleine Ergänzung zu Riley Avrons Antwort auf Gebietsschemaänderungen:

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
orxelm

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

Verwendungszweck :

button.centerTextAndImage(spacing: 10.0)
6
Hemang

Hier ein einfaches Beispiel für die Verwendung von imageEdgeInsets .__: Dadurch wird eine 30x30-Schaltfläche mit einem umsetzbaren Bereich, der um 10 Pixel größer ist (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)
1
Harris

Ich schreibe unten Code. Es funktioniert gut in der Produktversion. Unterstützen Sie 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()
}
}
1
Jules

Ein eleganter Weg in Swift 3 und besser zu verstehen:

override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    let leftMargin:CGFloat = 40
    let imgWidth:CGFloat = 24
    let imgHeight:CGFloat = 24
    return CGRect(x: leftMargin, y: (contentRect.size.height-imgHeight) * 0.5, width: imgWidth, height: imgHeight)
}

override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    let leftMargin:CGFloat = 80
    let rightMargin:CGFloat = 80
    return CGRect(x: leftMargin, y: 0, width: contentRect.size.width-leftMargin-rightMargin, height: contentRect.size.height)
}
override func backgroundRect(forBounds bounds: CGRect) -> CGRect {
    let leftMargin:CGFloat = 10
    let rightMargin:CGFloat = 10
    let topMargin:CGFloat = 10
    let bottomMargin:CGFloat = 10
    return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}
override func contentRect(forBounds bounds: CGRect) -> CGRect {
    let leftMargin:CGFloat = 5
    let rightMargin:CGFloat = 5
    let topMargin:CGFloat = 5
    let bottomMargin:CGFloat = 5
    return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}
0
teonicel

Die Swift 4.2-Version der Lösung wäre folgende:

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