Wyrównywanie tekstu i obrazu w UIButton z imageEdgeInsets i titleEdgeInsets

Chciałbym umieścić ikonę na lewo od dwóch linii tekstu tak, aby między obrazem a początkiem tekstu było około 2-3 pikseli przestrzeni. Sama kontrola jest wyrównana do środka poziomo (ustawiana za pomocą narzędzia Interface Builder)

Przycisk przypominałby coś takiego:

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

Próbuję skonfigurować to z contentEdgeInset, imageEdgeInsets i titleEdgeInsets bez skutku. Rozumiem, że wartość ujemna rozszerza krawędź, podczas gdy wartość dodatnia ją zmniejsza żeby zbliżyć się do środka.

Próbowałem:

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

Ale to nie wyświetla go poprawnie. Byłem dostosowywanie wartości, ale przechodząc od powiedzmy -5 do -10 po lewej stronie wartość wstawki nie wydaje się, aby przenieść go w oczekiwany sposób. -10 przesunie tekst w lewo, więc spodziewałem się, że -5 przesunie go w połowie z lewej strony, ale tak nie jest.

Jaka jest logika za wstawkami? Nie jestem zaznajomiony z umieszczaniem obrazów i powiązaną terminologią.

I used this SO pytanie jako punkt odniesienia, ale coś o moich wartościach nie jest w porządku. UIButton: jak wyśrodkować obraz i tekst za pomocą imageEdgeInsets i titleEdgeInsets?

Author: Community, 2010-12-30

11 answers

Zgadzam się, że dokumentacja na imageEdgeInsets i titleEdgeInsets powinna być lepsza, ale wymyśliłem, jak uzyskać prawidłowe pozycjonowanie bez uciekania się do prób i błędów.

Ogólna idea jest tutaj na to pytanie , ale to było, jeśli chcesz zarówno tekst i obraz wyśrodkowany. Nie chcemy, aby obraz i tekst były wyśrodkowane pojedynczo, chcemy, aby obraz i tekst były wyśrodkowane razem jako jedna jednostka. Jest to w rzeczywistości to, co UIButton już robi, więc po prostu musimy dostosować odstępy.

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

Zamieniłem to również w kategorię dla UIButton, więc będzie łatwy w użyciu:

UIButton + Pozycja.h

@interface UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;

@end

UIButton + Pozycja.m

@implementation UIButton(ImageTitleCentering)

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

@end

Więc teraz wszystko co muszę zrobić to:

[button centerButtonAndImageWithSpacing:10];
Za każdym razem dostaję to, czego potrzebuję. Koniec z ręcznym mieszaniem wkładek krawędziowych.

EDIT: Zamiana obrazu i tekstu

W odpowiedzi na @Javal w komentarzach

Używając tego samego mechanizmu, możemy zamienić obraz i tekst. Aby wykonać zamianę, po prostu użyj ujemnego odstępu, ale także Uwzględnij szerokość tekstu i obrazu. Wymaga to znajomości ramek i wykonania układu.

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

Oczywiście prawdopodobnie będziesz chciał zrobić fajną metodę do tego, potencjalnie dodając metodę drugiej kategorii, jest to pozostawione jako ćwiczenie dla czytelnika.

 339
Author: Kekoa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:50

Jestem trochę spóźniony na tę imprezę, ale myślę, że mam coś przydatnego do dodania.

Odpowiedź Kekoa jest świetna, ale, jak wspomina RonLugge, może sprawić, że przycisk przestanie szanować sizeToFit lub, co ważniejsze, może spowodować, że przycisk przyciśnie swoją zawartość, gdy jest wewnętrznie wielkości. Rany!

Po pierwsze,

Krótkie wyjaśnienie, jak wierzę, że imageEdgeInsets i titleEdgeInsets działają:

Docs for imageEdgeInsets mieć do powiedzenia, w część:

Użyj tej właściwości, aby zmienić rozmiar i położenie rzeczywistego prostokąta rysunku dla obrazu przycisku. Można określić inną wartość dla każdej z czterech wkładek (górna, lewa, dolna, prawa). Wartość dodatnia zmniejsza lub wstawia tę krawędź-przesuwając ją bliżej środka przycisku. Wartość ujemna rozszerza lub przewyższa tę krawędź.

Uważam, że ta dokumentacja została napisana wyobrażając sobie, że przycisk nie ma tytułu, tylko obraz. To sprawia, że o wiele więcej zmysł myśli w ten sposób i zachowuje się tak, jak zwykle. Zasadniczo ramka obrazu (lub tytuł, z titleEdgeInsets) jest przesuwana do wewnątrz dla wkładek pozytywnych i na zewnątrz dla wkładek negatywnych.

OK, i co z tego?

Dochodzę do tego! Oto, co masz domyślnie, ustawiając obraz i tytuł (ramka przycisku jest zielona, aby pokazać, gdzie jest):

Obraz startowy; brak spacji między tytułem a obrazem.

Gdy chcesz odstępy między obrazem a tytułem, nie powodując, że zmiażdżony, musisz ustawić cztery różne wkładki, po dwie na każdym obrazie i tytule. To dlatego, że nie chcesz zmieniać rozmiarów ramek tych elementów, a tylko ich pozycji. Kiedy zaczynasz myśleć w ten sposób, potrzebna zmiana do doskonałej kategorii Kekoa staje się jasna: {]}

@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

ale czekaj, mówisz, kiedy to robię, dostaję to:

Odstępy są dobre, ale obraz i tytuł znajdują się poza ramką widoku.

Oh yeah! Zapomniałem, lekarze ostrzegali mnie przed tym. Mówią, w część:

Ta właściwość jest używana tylko do pozycjonowania obrazu podczas layoutu. Przycisk nie używa tej właściwości do określania intrinsicContentSize i sizeThatFits:.

Ale tam jest właściwość, która może pomóc, i to jest contentEdgeInsets. docs do tego po części:

Przycisk używa tej właściwości do określenia intrinsicContentSize i sizeThatFits:.

Brzmi nieźle. Więc jeszcze raz podkręćmy kategorię:
@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

A co Ty dostać?

Odstępy i ramki są teraz poprawne.

Wygląda mi na zwycięzcę.

Pracujesz w Swift i nie chcesz w ogóle myśleć? Oto ostateczna wersja rozszerzenia w języku 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)
    }
}
 314
Author: ravron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 15:07:46

In interface Builder. Wybierz UIButton -> Inspektor atrybutów - > Edge=Title i zmodyfikuj wstawki krawędzi

 37
Author: Freeman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-20 14:38:54

Również jeśli chcesz zrobić coś podobnego do

Tutaj wpisz opis obrazka

Potrzebujesz

1.Ustaw wyrównanie poziome i pionowe dla przycisku na

Tutaj wpisz opis obrazka

  1. Znajdź wszystkie wymagane wartości i ustaw 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)];
    

To ułoży twój tytuł i obraz na przycisku.

Należy również pamiętać o aktualizacji tego na każdym przekaźniku


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)
            }
        }
    }
}
 32
Author: gbk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-23 12:54:47

Możesz uniknąć wielu kłopotów, używając tego ... ]}

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

Spowoduje to automatyczne wyrównanie całej zawartości do lewej (lub gdziekolwiek chcesz)

Swift 3:

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;
 26
Author: Nishant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 02:56:08

W Xcode 8.0 możesz to po prostu zrobić, zmieniając insets w Inspektorze rozmiaru.

Wybierz UIButton - > Inspektor atrybutów - > przejdź do inspektora rozmiaru i zmodyfikuj wkładki zawartości, obrazu i tytułu.

Tutaj wpisz opis obrazka

A jeśli chcesz zmienić obraz po prawej stronie, możesz po prostu zmienić właściwość semantyczną na Force Right-to-left w Inspektorze atrybutów .

Tutaj wpisz opis obrazka

 17
Author: Sahil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-29 04:22:15

Ja też trochę się spóźniłam na tę imprezę, ale chyba mam coś przydatnego do dodania: o).

Stworzyłem podklasę UIButton, której celem jest możliwość wyboru, gdzie znajduje się obraz przycisku, zarówno w pionie, jak i w poziomie.

Oznacza to, że można wykonać tego rodzaju przyciski : różne rodzaje przycisków

Tutaj szczegóły dotyczące tworzenia tych przycisków z moją klasą:

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)

Aby to zrobić, dodałem 2 atrybuty: imageVerticalAlignment i imageHorizontalAlignment. Oczywiście, jeśli twój przycisk mają tylko obraz lub tytuł ... w ogóle nie używaj tej klasy !

Dodałem również atrybut o nazwie imageToTitleSpacing, który pozwala dostosować odstęp między tytułem a obrazem.

Ta klasa stara się być kompatybilna, jeśli chcesz użyć imageEdgeInsets, titleEdgeInsets i contentEdgeInsets bezpośrednio lub w połączeniu z nowymi atrybutami układu.

Jak wyjaśnia nas @ravron, staram się jak najlepiej poprawić krawędź zawartości przycisku (jak widać z czerwonymi obramowaniami).

Można go również używać w interfejsie Budowniczy:

  1. Utwórz UIButton
  2. Zmień klasę przycisku
  3. dostosuj atrybuty Layoutable za pomocą "center", "top", "bottom", "left" lub "right" atrybuty przycisków

Tutaj kod (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
Author: gbitaudeau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-03 09:38:17

Mały dodatek do odpowiedzi Riley Avron na zmiany locale konta:

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)
    }
}
 7
Author: orxelm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-03 13:36:43

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

Użycie :

button.centerTextAndImage(spacing: 10.0)
 5
Author: Hemang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-29 11:09:37

Oto prosty przykład użycia imageEdgeInsets To spowoduje, że przycisk 30x30 z hittable obszaru 10 pikseli większy na całej drodze (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
Author: Harris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-10 20:48:15

Elegancki sposób w Swift 3 i lepiej zrozumieć:

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
Author: teonicel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-04 19:50:22