it-swarm.com.de

Wie setze ich das Bild in einem UIButton rechts neben den Text?

Ich möchte keine Unteransicht verwenden, wenn ich sie vermeiden kann. Ich möchte ein UIButton mit einem Hintergrundbild, Text und einem Bild darin. In diesem Moment befindet sich das Bild auf der linken Seite des Texts. Das Hintergrundbild, der Text und das Bild haben unterschiedliche Hervorhebungszustände.

266
jasongregori

Obwohl einige der vorgeschlagenen Antworten sehr kreativ und äußerst clever sind, lautet die einfachste Lösung wie folgt:

button.semanticContentAttribute = UIApplication.shared
    .userInterfaceLayoutDirection == .rightToLeft ? .forceLeftToRight : .forceRightToLeft

So einfach ist das. Als Bonus befindet sich das Bild in den Ländereinstellungen von rechts nach links auf der linken Seite.

EDIT : Da die Frage einige Male gestellt wurde, ist dies iOS 9 +.

211
Benjamin

Einfachste Lösung:

iOS 10 und höher, Swift:

button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

Vor iOS 10 Swift/Obj-C:

button.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.titleLabel.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.imageView.transform = CGAffineTransformMakeScale(-1.0, 1.0);
534
Liau Jian Jie

AKTUALISIERT FÜR XCODE 9 (über Interface Builder)

Es gibt einen einfacheren Weg vom Interface Builder . Wählen Sie den UIButton und wählen Sie diese Option in den View Utilities :

enter image description here

Das ist es! Schön und einfach!

[~ # ~] optional [~ # ~] - 2. Schritt:

Wenn Sie den Abstand zwischen dem Bild und dem Titel anpassen möchten, können Sie den Bildeinsatz hier ändern:

enter image description here

Ich hoffe, das hilft!

207
Victor Rius

Eine Unterklassifizierung von UIButton ist völlig unnötig. Stattdessen können Sie einfach einen hohen Wert für den linken Einschub für die Bildeinschübe und einen kleinen Wert für den rechten Einschub für den Titel festlegen. Etwas wie das:

button.imageEdgeInsets = UIEdgeInsetsMake(0., button.frame.size.width - (image.size.width + 15.), 0., 0.);
button.titleEdgeInsets = UIEdgeInsetsMake(0., 0., 0., image.size.width);
167
Ben Baron

Ich gebe Inspire48 die Gutschrift für diesen. Aufgrund seines Vorschlags und unter Berücksichtigung dieser anderen Frage kam ich auf diese Idee. Unterklasse UIButton und überschreibe diese Methoden.

@implementation UIButtonSubclass

- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    CGRect frame = [super imageRectForContentRect:contentRect];
    frame.Origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) -  self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame;
}

- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    CGRect frame = [super titleRectForContentRect:contentRect];
    frame.Origin.x = CGRectGetMinX(frame) - CGRectGetWidth([self imageRectForContentRect:contentRect]);
    return frame;
}

@end
88
jasongregori

Aktualisieren Sie einfach die Einfügungen, wenn der Titel geändert wird. Sie müssen den Einsatz mit einem gleichen und entgegengesetzten Einsatz auf der anderen Seite ausgleichen.

[thebutton setTitle:title forState:UIControlStateNormal];
thebutton.titleEdgeInsets = UIEdgeInsetsMake(0, -thebutton.imageView.frame.size.width, 0, thebutton.imageView.frame.size.width);
thebutton.imageEdgeInsets = UIEdgeInsetsMake(0, thebutton.titleLabel.frame.size.width, 0, -thebutton.titleLabel.frame.size.width);
76
Piotr Tomasik

Alle diese Antworten sind ab Januar 2016 nicht mehr erforderlich. Setzen Sie im Interface Builder die View Semantic auf Force Right-to-Left, oder wenn Sie programmatisch vorziehen, semanticContentAttribute = .forceRightToLeft Dadurch wird das Bild rechts von Ihrem Text angezeigt.

58
barndog

Im Interface Builder können Sie die Optionen Edge Insets für UIButton für drei Teile konfigurieren: Inhalt, Bild, Titel

enter image description hereenter image description here

Xcode 8:

enter image description here

51

pdate: Swift

class ButtonIconRight: UIButton {
    override func imageRect(forContentRect contentRect:CGRect) -> CGRect {
        var imageFrame = super.imageRect(forContentRect: contentRect)
        imageFrame.Origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
        return imageFrame
    }

    override func titleRect(forContentRect contentRect:CGRect) -> CGRect {
        var titleFrame = super.titleRect(forContentRect: contentRect)
        if (self.currentImage != nil) {
            titleFrame.Origin.x = super.imageRect(forContentRect: contentRect).minX
        }
        return titleFrame
    }
}

Originalantwort für Swift 2:

Eine Lösung, die alle horizontalen Ausrichtungen handhabt, mit einem Implementierungsbeispiel Swift). Bei Bedarf einfach in Objective-C übersetzen.

class ButtonIconRight: UIButton {
    override func imageRectForContentRect(contentRect:CGRect) -> CGRect {
        var imageFrame = super.imageRectForContentRect(contentRect)
        imageFrame.Origin.x = CGRectGetMaxX(super.titleRectForContentRect(contentRect)) - CGRectGetWidth(imageFrame)
        return imageFrame
    }

    override func titleRectForContentRect(contentRect:CGRect) -> CGRect {
        var titleFrame = super.titleRectForContentRect(contentRect)
        if (self.currentImage != nil) {
            titleFrame.Origin.x = CGRectGetMinX(super.imageRectForContentRect(contentRect))
        }
        return titleFrame
    }
}

Erwähnenswert ist auch, dass es recht gut mit Bild- und Titeleinfügungen umgehen kann.

Inspiriert von Jasongregori Antwort;)

23
Jean-Baptiste

Wenn dies in IBarButtonItem durchgeführt werden muss, sollte ein zusätzlicher Umbruch in der Ansicht verwendet werden
Dies wird funktionieren

let view = UIView()
let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
view.addSubview(button)
view.frame = button.bounds
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: view)

Das wird nicht funktionieren

let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
8
tt.Kilew

Hier ist die Lösung für UIButton mit zentriertem Inhalt. Dieser Code richtet das Bild rechtsbündig aus und ermöglicht die Verwendung von imageEdgeInsets und titleEdgeInsets für die wertvolle Positionierung.

enter image description here

Unterklasse UIButton mit Ihrer benutzerdefinierten Klasse und fügen Sie hinzu:

- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    CGRect frame = [super imageRectForContentRect:contentRect];
    CGFloat imageWidth = frame.size.width;
    CGRect titleRect = CGRectZero;
    titleRect.size = [[self titleForState:self.state] sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}];
    titleRect.Origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    frame.Origin.x = titleRect.Origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame;
}

- (CGRect)titleRectForContentRect:(CGRect)contentRect {
    CGFloat imageWidth = [self imageForState:self.state].size.width;
    CGRect frame = [super titleRectForContentRect:contentRect];
    frame.Origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    return frame;
}
7

Da die Transformationslösung in iOS 11 nicht funktioniert, habe ich mich für einen neuen Ansatz entschieden.

Durch Anpassen der Schaltflächen semanticContentAttribute wird das Bild rechts angezeigt, ohne dass ein Relayout erforderlich ist, wenn sich der Text ändert. Aus diesem Grund ist es die ideale Lösung. Allerdings brauche ich noch RTL-Unterstützung. Die Tatsache, dass eine App ihre Layoutrichtung in derselben Sitzung nicht ändern kann, behebt dieses Problem auf einfache Weise.

Trotzdem ist es ziemlich einfach.

extension UIButton {
    func alignImageRight() {
        if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
            semanticContentAttribute = .forceRightToLeft
        }
        else {
            semanticContentAttribute = .forceLeftToRight
        }
    }
}
4
cnotethegr8

Verlängerungsweg

Verwenden der Erweiterung, um das Bild auf der rechten Seite mit benutzerdefiniertem Versatz festzulegen

   extension UIButton {
    func addRightImage(image: UIImage, offset: CGFloat) {
        self.setImage(image, for: .normal)
        self.imageView?.translatesAutoresizingMaskIntoConstraints = false
        self.imageView?.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true
        self.imageView?.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -offset).isActive = true
    }
}
4
Musa almatri

Swift - Erweitern Sie den UiButton und setzen Sie diese Zeilen

    if let imageWidth = self.imageView?.frame.width {
        self.titleEdgeInsets = UIEdgeInsetsMake(0, -imageWidth, 0, imageWidth);
    }

    if let titleWidth = self.titleLabel?.frame.width {
        let spacing = titleWidth + 20
        self.imageEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, -spacing);
    }
3
Pramod

Aufbauend auf der eleganten Lösung von Piotr Tomasik: Wenn Sie ein bisschen Abstand haben möchten Fügen Sie dies dann wie folgt zwischen der Beschriftung der Schaltfläche und dem Bild in Ihre Edge-Einfügungen ein (kopieren Sie meinen Code hier, der für mich perfekt funktioniert):

    CGFloat spacing          = 3;
    CGFloat insetAmount      = 0.5 * spacing;

    // First set overall size of the button:
    button.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
    [button sizeToFit];

    // Then adjust title and image insets so image is flipped to the right and there is spacing between title and image:
    button.titleEdgeInsets   = UIEdgeInsetsMake(0, -button.imageView.frame.size.width - insetAmount, 0,  button.imageView.frame.size.width  + insetAmount);
    button.imageEdgeInsets   = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width + insetAmount, 0, -button.titleLabel.frame.size.width - insetAmount);

Danke Piotr für deine Lösung!

Erik

3

Nahm @ Piotrs Antwort und verwandelte sie in eine Swift Erweiterung. Stellen Sie sicher, dass Sie das Bild und den Titel festgelegt haben, bevor Sie dies aufrufen, damit die Größe der Schaltfläche korrekt ist.

extension UIButton {

/// Makes the ``imageView`` appear just to the right of the ``titleLabel``.
func alignImageRight() {
    if let titleLabel = self.titleLabel, imageView = self.imageView {
        // Force the label and image to resize.
        titleLabel.sizeToFit()
        imageView.sizeToFit()
        imageView.contentMode = .ScaleAspectFit

        // Set the insets so that the title appears to the left and the image appears to the right. 
        // Make the image appear slightly off the top/bottom edges of the button.
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: -1 * imageView.frame.size.width,
            bottom: 0, right: imageView.frame.size.width)
        self.imageEdgeInsets = UIEdgeInsets(top: 4, left: titleLabel.frame.size.width,
            bottom: 4, right: -1 * titleLabel.frame.size.width)
    }
}

}

2
Nick Yap

Eine Swift Option, die macht, was Sie wollen, ohne mit irgendwelchen Einsätzen zu spielen:

class RightImageButton: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let  textSize = titleLabel?.intrinsicContentSize(),
                imageSize = imageView?.intrinsicContentSize() {
            let wholeWidth = textSize.width + K.textImageGap + imageSize.width
            titleLabel?.frame = CGRect(
                x: round(bounds.width/2 - wholeWidth/2),
                y: 0,
                width: ceil(textSize.width),
                height: bounds.height)
            imageView?.frame = CGRect(
                x: round(bounds.width/2 + wholeWidth/2 - imageSize.width),
                y: RoundRetina(bounds.height/2 - imageSize.height/2),
                width: imageSize.width,
                height: imageSize.height)
        }
    }

    struct K {
        static let textImageGap: CGFloat = 5
    }

}
2
Chris

Layouts unterordnen und übersteuernSubviews sind wahrscheinlich der beste Weg, dies zu tun.

Referenziert von: iPhone UIButton - Bildposition

1
FeifanZ

Die hier genannten Lösungen funktionierten nicht mehr, nachdem ich das automatische Layout aktiviert hatte . Ich musste mir selbst einfallen lassen:

Unterklasse UIButton und überschreibe layoutSubviews Methode:

//
//  MIThemeButtonImageAtRight.m
//  Created by Lukasz Margielewski on 7/9/13.
//

#import "MIThemeButtonImageAtRight.h"

static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets);

@implementation MIThemeButtonImageAtRight

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGRect contentFrame = CGRectByApplyingUIEdgeInsets(self.bounds, self.contentEdgeInsets);

    CGRect frameIcon = self.imageView.frame;
    CGRect frameText = self.titleLabel.frame;

    frameText.Origin.x = CGRectGetMinX(contentFrame) + self.titleEdgeInsets.left;
    frameIcon.Origin.x = CGRectGetMaxX(contentFrame) - CGRectGetWidth(frameIcon);

    self.imageView.frame = frameIcon;
    self.titleLabel.frame = frameText;
}

@end

static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets){

    CGRect f = frame;

    f.Origin.x += insets.left;
    f.size.width -= (insets.left + insets.right);
    f.Origin.y += (insets.top);
    f.size.height -= (insets.top + insets.bottom);

    return f;

}

Ergebnis:

enter image description here

1
Lukasz

Nachdem ich mehrere Lösungen aus dem Internet ausprobiert hatte, erfüllte ich nicht die genauen Anforderungen. Also schrieb ich einen benutzerdefinierten Utility-Code. Posten, um jemandem in Zukunft zu helfen. Getestet am Swift 4.2

// This function should be called in/after viewDidAppear to let view render
    func addArrowImageToButton(button: UIButton, arrowImage:UIImage = #imageLiteral(resourceName: "my_image_name") ) {
        let btnSize:CGFloat = 32
        let imageView = UIImageView(image: arrowImage)
        let btnFrame = button.frame
        imageView.frame = CGRect(x: btnFrame.width-btnSize-8, y: btnFrame.height/2 - btnSize/2, width: btnSize, height: btnSize)
        button.addSubview(imageView)
        //Imageview on Top of View
        button.bringSubviewToFront(imageView)
    }
0
jeet.chanchawat

Swift 3:

open override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    var frame = super.imageRect(forContentRect: contentRect)
    let  imageWidth = frame.size.width
    var titleRect = CGRect.zero
    titleRect.size = self.title(for: self.state)!.size(attributes: [NSFontAttributeName: self.titleLabel!.font])
    titleRect.Origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    frame.Origin.x = titleRect.Origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame
}

open override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    var frame = super.titleRect(forContentRect: contentRect)
    if let imageWidth = self.image(for: self.state)?.size.width {
        frame.Origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    }
    return frame
}
0

Swift 3. Migrationslösung von jasongregori

class ButtonIconRight: UIButton {
        override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
            var imageFrame = super.imageRect(forContentRect: contentRect)
           imageFrame.Origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
        return imageFrame
        }

        override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
            var titleFrame = super.titleRect(forContentRect: contentRect)
            if (self.currentImage != nil) {
                titleFrame.Origin.x = super.imageRect(forContentRect: contentRect).minX
            }
            return titleFrame
        }
0
Sourabh Sharma

Wie wäre es mit Einschränkungen? Im Gegensatz zu semanticContentAttribute wird die Semantik nicht geändert. So etwas vielleicht:

 button.rightAnchorconstraint(equalTo: button.rightAnchor).isActive = true

oder in Ziel-C:

[button.imageView.rightAnchor constraintEqualToAnchor:button.rightAnchor].isActive = YES;

Vorsichtsmaßnahmen: Ungetestet, iOS 9+

0