Wie platziere ich das Bild in einem UIButton auf der rechten Seite des Textes?

300

Ich möchte keine Unteransicht verwenden, wenn ich dies vermeiden kann. Ich möchte ein UIButtonmit einem Hintergrundbild, Text und einem Bild darin. Wenn ich das mache, befindet sich das Bild gerade auf der linken Seite des Textes. Das Hintergrundbild, der Text und das Bild haben unterschiedliche Hervorhebungszustände.

Jasongregori
quelle
Um der wachsenden Liste hier einen weiteren "Hack" hinzuzufügen: Sie können den Attributtitel der Schaltfläche auf eine Attributzeichenfolge setzen, die Ihren Schaltflächentitel + ein Leerzeichen + das Bild enthält (als NSTextAttachment). Möglicherweise müssen Sie die Grenzen des Anhangs anpassen , damit er wie gewünscht ausgerichtet wird (siehe stackoverflow.com/questions/26105803/… ).
Manav

Antworten:

266

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 links von links nach links.

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

Benjamin
quelle
89
Ich kann nicht glauben, dass diese Antwort akzeptiert wurde. Niemand macht Lokalisierungen für ihre Anwendungen?
Zoltán
6
@pallzoltan: Dies beantwortet die Frage (dh "Wie platziere ich das Bild in einem UIButton auf der rechten Seite des Textes?"). Was hat Lokalisierung damit zu tun?
Benjamin
17
Es gibt nicht viele Situationen, in denen Sie nicht möchten, dass Ihr Layout in RTL-Sprachen "umgedreht" wird. Direkte Einstellung semanticContentAttributeist nur ein Hack / Workaround, keine echte Lösung.
Zoltán
6
Mein Ansatz ist, dass Sie nicht wissen, was die Person, die die Frage stellt, baut, daher ist es immer besser, mit Flexibilität für das Layout zu zählen.
Zoltán
2
@ Zoltán Lokalisierung ist kein Problem, invertieren Sie einfach die Eigenschaft abhängig vom aktuellen Gebietsschema.
Manmal
561

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);
Liau Jian Jie
quelle
8
Ich habe dies für die Titelansicht der Navigationsleiste verwendet und es gab einen Fehler. Es ist in Ordnung, wenn es zum ersten Mal geladen wird, aber wenn Sie einen Ansichts-Controller drücken und ihn öffnen, wird der Titel gespiegelt.
Funktion7
@WoominJoshPark Interessant ... Ich kann nur vermuten, dass dies daran liegt, dass die Transformation intern für Navigations-Pop-Animationen animiert wird.
Liau Jian Jie
1
Ich fand heraus, wenn dies Beschwerden über Autolayout-Einschränkungskonflikte zur Laufzeit verursacht, kann es behoben werden, indem dies in layoutSubviews ()
Vlad
1
Wie kann ich mehr Platz zwischen Text und Bild schaffen?
Rohinb
2
@rohinb @ jose920405 Versuchen Sie, ImageEdgeInsets und ContentEdgeInsets für das Auffüllen festzulegen (beachten Sie, dass sie umgekehrt wurden). Zum Beispiel button.ImageEdgeInsets = new UIEdgeInsets(0, -leftPadding, 0, leftPadding); button.ContentEdgeInsets = new UIEdgeInsets(0, 0, 0, leftPadding);. Das ist in Xamarin, sollte aber leicht genug in Swift / Obj-C übersetzt werden können.
Lee Richardson
268

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 unter View Utilities> Semantic :

links nach rechts Geben Sie hier die Bildbeschreibung ein 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 :

Geben Sie hier die Bildbeschreibung ein

Ich hoffe, das hilft!

Victor Rius
quelle
2
In Xcode 9.0 Beta 5 (9M202q) sehen Sie das Ergebnis leider nur zur Laufzeit - im Storyboard wird das Bild weiterhin links angezeigt. Beachten Sie auch, dass aus diesem Grund einige Versuche erforderlich sind, um die richtigen Einfügungen festzulegen.
PDK
3
Bitte machen Sie es nicht so - dies unterbricht die Lokalisierung für Sprachen von rechts nach links.
Jsadler
169

Das Unterklassen von UIButton ist völlig unnötig. Stattdessen können Sie einfach einen hohen linken Einschubwert für die Bildeinsätze und einen kleinen 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);
Ben Baron
quelle
3
Es hat funktioniert, aber denken Sie daran, dass Sie es heute mit Autolayout auf viewDidAppear und nicht auf viewDidLoad tun müssen
Hola Soja Edu Feliz Navidad
91

Ich gebe Inspire48 die Ehre dafür. Aufgrund seines Vorschlags und der Betrachtung dieser anderen Frage kam ich auf diese Idee. Unterklasse UIButton und überschreiben 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
Jasongregori
quelle
3
UIButton ist ein Klassencluster und sollte nicht in Unterklassen unterteilt werden.
Scott Berrevoets
50
Dies ist nicht der Fall. In der Dokumentation wird die Unterklasse explizit erwähnt und es werden Methoden bereitgestellt, die Sie für das benutzerdefinierte Layoutverhalten überschreiben sollten.
Tark
2
developer.apple.com/library/ios/documentation/uikit/reference/… buttonWithType If you subclass UIButton, this method does not return an instance of your subclass. If you want to create an instance of a specific subclass, you must alloc/init the button directly und backgroundRectForBoundsUnterklassen, die benutzerdefinierte Hintergrundverzierungen bereitstellen, können diese Methode überschreiben und ein modifiziertes Begrenzungsrechteck zurückgeben, um zu verhindern, dass die Schaltfläche über benutzerdefinierte Inhalte zeichnet. " Methoden, aber ich nehme an, sie haben nichts gegen Unterklassen.
Christophercotton
1
Sieht so aus, als wäre diese Formel besser für das Spiegeln von Bilderrahmen: frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left - frame.origin.x;Sie funktioniert besser für UIControlContentHorizontalAlignmentCenterund andere ...
k06a
@ GwendalRoué Nur weil es kürzer ist, heißt das nicht, dass es besser ist. Es ist ein hackigerer Weg, und die Schaltfläche ignoriert tatsächliche Einfügungen und kann in Sprachen von rechts nach links unterbrochen werden. Mit dieser Antwort haben Sie die volle Kontrolle über das Layout
Accatyyc
76

Aktualisieren Sie einfach die Einfügungen, wenn der Titel geändert wird. Sie müssen den Einschub durch einen gleichen und entgegengesetzten Einschub auf der anderen Seite kompensieren.

[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);
Piotr Tomasik
quelle
3
Vielleicht möchten Sie [thebutton.titleLabel sizeToFit];vorher hinzufügen . Die Breite kann Null sein, wenn Sie kein Layout ausgelöst haben. Gleiches gilt für die Bildgröße (verwenden Sie einfach die UIImage.size anstelle der imageView-Größe)
delrox
@delrox guter Punkt. Kann verwenden titleWidth = [self.titleLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, self.bounds.size.height)].width;(oder wenn Sie besorgt sind, dass der Schaltflächenrahmen noch nicht eingerichtet ist, verwenden Sie CGFLOAT_MAX auch für die Höhe) undimageWidth = self.currentImage.size.width;
Dave Goldman
1
Funktioniert perfekt auf viewDidLayoutSubviews
Gwendal Roué
Ich musste dies in layoutSubviewsmeine UITableViewCellUnterklasse aufnehmen, aber es funktioniert gut. Vielen Dank!
RyanG
60

Alle diese Antworten ab Januar 2016 sind nicht erforderlich. Stellen Sie im Interface Builder die Ansichtssemantik auf ein Force Right-to-Leftoder wenn Sie eine programmatische Methode bevorzugen, semanticContentAttribute = .forceRightToLeftwird das Bild rechts neben Ihrem Text angezeigt.

Barndog
quelle
5
Leider werden ios, die älter als 9 sind, nicht unterstützt. Trotzdem eine nette Antwort.
Eddie
1
Ich bin traurig zu berichten, dass das Festlegen dieser Option auf einem UIButton, der dann für UIBarButtonItem verwendet wird, zu keiner Änderung geführt hat.
Amelia
Wie @Amelia erwähnt, funktioniert es nicht, wenn Sie anrufen UIBarButtonItem(customView: button), aber es funktioniert, wenn Sie die Schaltfläche in eine leere Ansicht
einschließen
@ tt.Kilew, mit XCode 8.1 funktioniert es. Ich setze den uiButton.semanticContentAttribute = .forceRightToLeft und gebe let nextButton = UIBarButtonItem (customView: uiButton)
Eugene Biryukov
53

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

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Xcode 8:

Geben Sie hier die Bildbeschreibung ein

Gennadiy Ryabkin
quelle
3
eigentlich beste Antwort aus meiner Sicht diese stackoverflow.com/a/39013315/1470374 ))
Gennadiy Ryabkin
25

Update: Swift 3

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

Ursprüngliche Antwort für Swift 2:

Eine Lösung, die alle horizontalen Ausrichtungen mit einem Swift-Implementierungsbeispiel behandelt. Übersetzen Sie bei Bedarf einfach in Objective-C.

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

Jean-Baptiste
quelle
1
Diese Lösung funktionierte für mich, mein Bild benötigte jedoch etwas Platz, sodass ich den folgenden Code hinzufügte: self.contentEdgeInsets = UIEdgeInsetsMake (10.0, 10.0, 10.0, 10.0)
user1354603
1
Ich mag diesen Weg, weil Sie @IBDesignableder Klasse hinzufügen und sehen können, wie sie zur Entwurfszeit umgedreht wird.
James Toomey
Ich bevorzuge diese Lösung, weil sie sogar in der Navigationsleiste funktioniert.
El Horrible
10

Wenn dies in UIBarButtonItem durchgeführt werden muss , sollte ein zusätzlicher Wrapping in der Ansicht verwendet werden.
Dies funktioniert

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)
tt.Kilew
quelle
7

Hier ist eine Lösung für UIButtonInhalte mit zentrierter Ausrichtung. Dieser Code macht das Bild rechtsbündig und ermöglicht die Verwendung imageEdgeInsetsund titleEdgeInsetswertvolle Positionierung.

Geben Sie hier die Bildbeschreibung ein

Unterklasse UIButtonmit 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;
}
Vitaliy Gozhenko
quelle
1
Sie können auch IBDESIGNABLE zum Klassenkopf hinzufügen, um es in der Geschichte yadi.sk/i/fd6Si-BJqzCFD
Nikolay Shubenkov
6

Da die Transformationslösung in iOS 11 nicht funktioniert, habe ich beschlossen, einen neuen Ansatz zu schreiben.

Durch Anpassen der Schaltflächen sehen semanticContentAttributewir das Bild schön rechts, ohne dass wir es weiterleiten müssen, wenn sich der Text ändert. Aus diesem Grund ist es die ideale Lösung. Ich brauche jedoch 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
        }
    }
}
cnotethegr8
quelle
6

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
    }
}
Musa almatri
quelle
4

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);
    }
Pramod
quelle
3

Aufbauend auf der eleganten Lösung von Piotr Tomasik: Wenn Sie auch einen gewissen Abstand zwischen der Tastenbeschriftung und dem Bild haben möchten, fügen Sie diesen wie folgt in Ihre Kanteneinfügungen ein (kopieren Sie meinen Code hier, der perfekt für mich 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

Erik van der Neut
quelle
@lulian: Ich habe stattdessen kürzlich die Lösung von Liau Jian Jie verwendet (die hier akzeptierte Antwort), und das funktioniert hervorragend und ist eine sehr elegante Lösung.
Erik van der Neut
Das funktioniert auch bei mir nicht, da es die Ausrichtung des Textes ändert.
Iulian Onofrei
3

Mach es dir selbst. Xcode10, swift4,

Für programmgesteuertes UI-Design

Geben Sie hier die Bildbeschreibung ein

 lazy var buttonFilter : ButtonRightImageLeftTitle = {
    var button = ButtonRightImageLeftTitle()
    button.setTitle("Playfir", for: UIControl.State.normal)
    button.setImage(UIImage(named: "filter"), for: UIControl.State.normal)
    button.backgroundColor = UIColor.red
    button.contentHorizontalAlignment = .left
    button.titleLabel?.font = UIFont.systemFont(ofSize: 16)
    return button
}()

Kanteneinfügungswerte werden auf ein Rechteck angewendet, um den durch dieses Rechteck dargestellten Bereich zu verkleinern oder zu erweitern. In der Regel werden Kanteneinsätze während des Ansichtslayouts verwendet, um den Rahmen der Ansicht zu ändern. Positive Werte bewirken, dass der Rahmen um den angegebenen Betrag eingefügt (oder verkleinert) wird. Negative Werte bewirken, dass der Frame um den angegebenen Betrag versetzt (oder erweitert) wird.

class ButtonRightImageLeftTitle: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        guard imageView != nil else { return }

        imageEdgeInsets = UIEdgeInsets(top: 5, left: (bounds.width - 35), bottom: 5, right: 5)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: -((imageView?.bounds.width)! + 10), bottom: 0, right: 0 )

    }
}

für das StoryBoard-UI-Design

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Nazmul Hasan
quelle
Gibt es eine Möglichkeit, es eleganter zu machen?
Zaporozhchenko Oleksandr
2

Unterklassen und übergeordnetes LayoutSubviews sind wahrscheinlich der beste Weg.

Referenziert von: iPhone UIButton - Bildposition

FeifanZ
quelle
3
Es gibt absolut keine Probleme, UIButton zu unterklassifizieren.
Nonamelive
2

Nahm @ Piotrs Antwort und machte es zu einer Swift-Erweiterung. Stellen Sie sicher, dass Sie das Bild und den Titel festlegen, bevor Sie dies aufrufen, damit die Größe der Schaltfläche richtig 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)
    }
}

}}

Nick Yap
quelle
2

Eine schnelle Option, die macht, was Sie wollen, ohne mit Insets 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
    }

}
Chris
quelle
1

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

Unterklasse UIButton und Override- layoutSubviewsMethode:

//
//  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:

Geben Sie hier die Bildbeschreibung ein

Lukasz
quelle
1

schnelle 3.0 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
        }
Sourabh Sharma
quelle
1

Ich habe mich entschieden, die Standard-Schaltflächenbildansicht nicht zu verwenden, da sich die vorgeschlagenen Lösungen zum Verschieben hackig anfühlten. Dies brachte mir die gewünschte Ästhetik und es ist intuitiv, den Knopf durch Ändern der Einschränkungen neu zu positionieren:

extension UIButton {
    func addRightIcon(image: UIImage) {
        let imageView = UIImageView(image: image)
        imageView.translatesAutoresizingMaskIntoConstraints = false

        addSubview(imageView)

        let length = CGFloat(15)
        titleEdgeInsets.right += length

        NSLayoutConstraint.activate([
            imageView.leadingAnchor.constraint(equalTo: self.titleLabel!.trailingAnchor, constant: 10),
            imageView.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
            imageView.widthAnchor.constraint(equalToConstant: length),
            imageView.heightAnchor.constraint(equalToConstant: length)
        ])
    }
}

Taste mit Rechtspfeil

Mark Hennings
quelle
Dies reagiert nicht auf Tippen, der Text wird dunkler, das Bild jedoch nicht
Teddy K
0

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
}
Alexander Volkov
quelle
0

Wie wäre es mit Einschränkungen? Im Gegensatz zu semanticContentAttribute ändern sie die Semantik nicht. 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+

Rock Workinghouse
quelle
0

Versuchen Sie den folgenden Code, um das Bild innerhalb von UIButton nach rechts auszurichten

btn.contentHorizontalAlignment = .right
Dhaval H. Nena
quelle
Darum hat der Autor nicht gebeten.
Mateusz
0

Nachdem ich mehrere Lösungen aus dem Internet ausprobiert hatte, erreichte ich nicht die genaue Anforderung. Also habe ich benutzerdefinierten Dienstprogrammcode geschrieben. Posting, um jemandem in Zukunft zu helfen. Getestet auf schnell 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)
    }
jeet.chanchawat
quelle
0

Für dieses Problem können Sie UIView in "label with UIImage view" erstellen, die UIView-Klasse als UIControl festlegen und IBAction als Tuch-Up-Side erstellen

Geben Sie hier die Bildbeschreibung ein

Sushil Vyas
quelle
0

Swift 4 & 5

Ändern Sie die Richtung des UIButton-Bildes (RTL und LTR).

extension UIButton {
    func changeDirection(){
       isArabic ? (self.contentHorizontalAlignment = .right) : (self.contentHorizontalAlignment = .left)
        // left-right margin 
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    }
}
Rashid Latif
quelle
Was ist Utility?
Byron Coetsee
Ich entferne nur das Dienstprogramm. Es ist eine Klasse in meinem Code, in der ich überprüfen kann, ob die ausgewählte Sprache Arabisch oder Englisch ist
Rashid Latif
0

Xcode 11.4 Swift 5.2

Für alle, die versuchen, den Stil der Zurück-Schaltfläche mit dem Chevron wie folgt zu spiegeln:

Geben Sie hier die Bildbeschreibung ein

import UIKit

class NextBarButton: UIBarButtonItem {

    convenience init(target: Any, selector: Selector) {

        // Create UIButton
        let button = UIButton(frame: .zero)

        // Set Title
        button.setTitle("Next", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 17)

        // Configure Symbol
        let config = UIImage.SymbolConfiguration(pointSize: 19.0, weight: .semibold, scale: .large)
        let image = UIImage(systemName: "chevron.right", withConfiguration: config)
        button.setImage(image, for: .normal)

        // Add Target
        button.addTarget(target, action: selector, for: .touchUpInside)

        // Put the Image on the right hand side of the button
        // Credit to liau-jian-jie for this part
        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)

        // Customise spacing to match system Back button
        button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: -18.0, bottom: 0.0, right: 0.0)
        button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -12.0, bottom: 0.0, right: 0.0)

        self.init(customView: button)
    }
}

Implementierung:

override func viewDidLoad() {
    super.viewDidLoad()
    let nextButton = NextBarButton(target: self, selector: #selector(nextTapped))
    navigationItem.rightBarButtonItem = nextButton
}

@objc func nextTapped() {
    // your code
}
rbaldwin
quelle
0

Am Ende habe ich eine benutzerdefinierte Schaltfläche erstellt, mit der Sie das Bild aus dem Inspektor festlegen können. Unten ist mein Code:

import UIKit

@IBDesignable
class CustomButton: UIButton {

    @IBInspectable var leftImage: UIImage? = nil
    @IBInspectable var gapPadding: CGFloat = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }

    func setup() {

        if(leftImage != nil) {
            let imageView = UIImageView(image: leftImage)
            imageView.translatesAutoresizingMaskIntoConstraints = false

            addSubview(imageView)

            let length = CGFloat(16)
            titleEdgeInsets.left += length

            NSLayoutConstraint.activate([
                imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: gapPadding),
                imageView.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
                imageView.widthAnchor.constraint(equalToConstant: length),
                imageView.heightAnchor.constraint(equalToConstant: length)
            ])
        }
    }
}

Sie können den Wert von Gap Padding im Inspector anpassen, um den Abstand zwischen Text und Bild anzupassen.

PS: Verwendet einen Codeteil aus der Antwort von @Mark Hennings

Mahendra Liya
quelle