Come posso mettere l'immagine sul lato destro del testo in un UIButton?


300

Non voglio usare un sottoview se posso evitarlo. Voglio un UIButtoncon un'immagine di sfondo, testo e un'immagine in esso. In questo momento, quando lo faccio, l'immagine si trova sul lato sinistro del testo. L'immagine di sfondo, il testo e l'immagine hanno tutti stati di evidenziazione diversi.


Per aggiungere un altro "hack" all'elenco crescente qui: è possibile impostare l'attributoTitolo del pulsante su una stringa attribuita contenente il titolo del pulsante + uno spazio + l'immagine (come NSTextAttachment). Potrebbe essere necessario modificare i limiti dell'allegato per allinearlo come desiderato (consultare stackoverflow.com/questions/26105803/… ).
Manav,

Risposte:


266

Nonostante alcune delle risposte suggerite siano molto creative ed estremamente intelligenti, la soluzione più semplice è la seguente:

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

Così semplice. Come bonus, l'immagine sarà sul lato sinistro in locali da destra a sinistra.

EDIT : poiché la domanda è stata posta alcune volte, si tratta di iOS 9 + .


89
Non posso credere che questa risposta sia stata accettata. Nessuno localizza le loro applicazioni?
Zoltán,

6
@pallzoltan: questo risponde alla domanda (es. "Come posso mettere l'immagine sul lato destro del testo in un UIButton?"). Cosa c'entra la localizzazione con questo?
Benjamin,

17
Non ci sono molte situazioni in cui non si desidera "capovolgere" il layout nelle lingue RTL. L'impostazione diretta semanticContentAttributeè solo un trucco / soluzione alternativa, non una vera soluzione.
Zoltán,

6
Il mio approccio è che non sai cosa sta costruendo la persona che pone la domanda, quindi è sempre meglio contare con flessibilità per il layout.
Zoltán,

2
La localizzazione di @ Zoltán non è un problema, basta invertire la proprietà in base alle impostazioni locali correnti.
manmal

561

La soluzione più semplice:

iOS 10 e versioni successive, 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)

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

8
L'ho usato per la vista del titolo della barra di navigazione e c'era un problema tecnico. Va bene quando viene caricato per la prima volta, ma quando si preme un controller di visualizzazione e lo si apre, il titolo viene capovolto.
funct7,

@WoominJoshPark Interessante ... Posso solo immaginare che ciò sia dovuto al fatto che la trasformazione è animata internamente per le animazioni pop di navigazione.
Liau Jian Jie,

1
Ho scoperto che se ciò sta causando lamentele sui conflitti di vincolo di autolayout in fase di esecuzione, potrebbe essere risolto aggiungendo questo in layoutSubviews ()
Vlad

1
Come posso mettere più spazio tra il testo e l'immagine?
Rohinb,

2
@rohinb @ jose920405 Prova a impostare ImageEdgeInsets e ContentEdgeInsets per il riempimento (tenendo presente che sono stati invertiti). Per esempio button.ImageEdgeInsets = new UIEdgeInsets(0, -leftPadding, 0, leftPadding); button.ContentEdgeInsets = new UIEdgeInsets(0, 0, 0, leftPadding);. È in Xamarin, ma dovrebbe tradursi in Swift / Obj-C abbastanza facilmente.
Lee Richardson,

269

AGGIORNATO PER XCODE 9 (tramite Interface Builder)

C'è un modo più semplice da Interface Builder .

Seleziona il pulsante UIB e seleziona questa opzione in Visualizza Utilità> Semantica :

da sinistra a destra inserisci qui la descrizione dell'immagine Questo è tutto! Bello e semplice!

OPZIONALE - 2 ° passaggio:

Se si desidera regolare la spaziatura tra l'immagine e il titolo, è possibile modificare l' immagine inserita qui:

inserisci qui la descrizione dell'immagine

Spero che aiuti!


2
In Xcode 9.0 beta 5 (9M202q), sfortunatamente vedi solo il risultato in fase di esecuzione: nello storyboard mostra ancora l'immagine a sinistra. Si noti inoltre che per questo motivo sono necessari alcuni tentativi ed errori per impostare gli inserti corretti.
PDK,

3
Per favore, non farlo in questo modo - questo interrompe la localizzazione per le lingue da destra a sinistra.
jsadler,

169

La sottoclasse di UIButton è completamente inutile. Invece puoi semplicemente impostare un valore di inserto sinistro alto per gli inserti immagine e un inserto destro piccolo per il titolo. Qualcosa come questo:

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

3
Ha funzionato, ma ricorda che oggi con autolayout devi farlo su viewDidAppear e non su viewDidLoad
Hola Soy Edu Feliz Navidad

91

Sto dando a Inspire48 il merito per questo. Sulla base del suo suggerimento e guardando quell'altra domanda, mi è venuta in mente questa. Sottoclasse UIButton e sovrascrive questi metodi.

@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

3
UIButton è un cluster di classe e non deve essere sottoclassato.
Scott Berrevoets,

50
Ciò non è vero, la documentazione menziona esplicitamente la sottoclasse e fornisce metodi che è necessario ignorare per il comportamento del layout personalizzato.
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 e le backgroundRectForBoundssottoclassi che forniscono ornamenti di sfondo personalizzati possono sovrascrivere questo metodo e restituire un rettangolo di limiti modificato per impedire al pulsante di disegnare su qualsiasi contenuto personalizzato. metodi, ma suppongo che non dispiacciano le sottoclassi.
christophercotton,

1
Sembra che questa formula sia migliore per il mirroring della cornice immagine: frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left - frame.origin.x;funziona meglio per gli UIControlContentHorizontalAlignmentCenteraltri ...
k06a

@ GwendalRoué Solo perché è più corto non significa che sia meglio. È un modo più hacker e fa sì che il pulsante ignori le inserzioni effettive e possa rompersi nelle lingue da destra a sinistra. Con questa risposta hai il pieno controllo del layout
Accatyyc,

76

Aggiorna semplicemente le inserzioni quando il titolo viene modificato. È necessario compensare l'inserto con un inserto uguale e opposto sull'altro lato.

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

3
Potresti voler aggiungere [thebutton.titleLabel sizeToFit];prima. La larghezza può essere zero se non hai attivato un layout. Lo stesso vale per la dimensione dell'immagine (basta usare UIImage.size invece della dimensione imageView)
delrox

@delrox buon punto. Puoi usare titleWidth = [self.titleLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, self.bounds.size.height)].width;(o se sei preoccupato per la cornice dei pulsanti non ancora stabilita, usa anche CGFLOAT_MAX per l'altezza) eimageWidth = self.currentImage.size.width;
Dave Goldman,

1
Funziona perfettamente su viewDidLayoutSubviews
Gwendal Roué,

Ho dovuto inserire questo layoutSubviews nella mia UITableViewCellsottoclasse, ma funziona bene. Grazie!
RyanG,

60

Tutte queste risposte, a partire da gennaio 2016, non sono necessarie. In Interface Builder, imposta Visualizza semantica su Force Right-to-Left, o se preferisci il modo programmatico, semanticContentAttribute = .forceRightToLeftCiò farà apparire l'immagine a destra del testo.


5
Purtroppo non supporta iOS di età superiore a 9. Comunque bella risposta, comunque.
Eddie,

1
Sono triste a dire che l'impostazione su un UIButton che viene quindi utilizzato per UIBarButtonItem non ha comportato alcuna modifica.
Amelia,

Come accennato da @Amelia, non funziona se chiami UIBarButtonItem(customView: button), ma funzionerà se
avvolgi il

@ tt.Kilew, usando XCode 8.1 puoi farlo funzionare. Ho impostato uiButton.semanticContentAttribute = .forceRightToLeft e fornisco let nextButton = UIBarButtonItem (customView: uiButton)
Eugene Biryukov,


25

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

Risposta originale per Swift 2:

Una soluzione che gestisce tutti gli allineamenti orizzontali, con un esempio di implementazione Swift. Basta tradurre in Objective-C se necessario.

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

Vale anche la pena notare che gestisce abbastanza bene le immagini e gli inserimenti dei titoli.

Ispirato dalla risposta jasongregori;)


1
Questa soluzione ha funzionato per me, tuttavia la mia immagine aveva bisogno di spazio attorno ad essa, quindi ho aggiunto il seguente codice: self.contentEdgeInsets = UIEdgeInsetsMake (10.0, 10.0, 10.0, 10.0)
user1354603

1
Mi piace in questo modo perché puoi aggiungerlo @IBDesignablealla classe e vederlo capovolto in fase di progettazione.
James Toomey,

Preferisco questa soluzione perché funziona anche quando viene inserita nella barra di navigazione.
El Horrible,

10

Se questa necessità di essere fatto in UIBarButtonItem , involucro supplementare in vista deve essere utilizzato
questo lavoro

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)

Questo non funzionerà

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)

7

Ecco una soluzione UIButtoncon contenuto allineato al centro. Questo codice rende l'immagine allineata a destra e consente l'utilizzo imageEdgeInsetse il titleEdgeInsetsposizionamento prezioso.

inserisci qui la descrizione dell'immagine

Sottoclasse UIButtoncon la tua classe personalizzata e aggiungi:

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

1
Inoltre puoi aggiungere IBDESIGNABLE all'intestazione della classe per vederlo nella storyborad yadi.sk/i/fd6Si-BJqzCFD
Nikolay Shubenkov

6

Dato che la soluzione di trasformazione non funziona in iOS 11, ho deciso di scrivere un nuovo approccio.

Regolazione dei pulsanti semanticContentAttribute ci consente di visualizzare l'immagine a destra senza dover uscire se il testo cambia. Per questo motivo è la soluzione ideale. Tuttavia ho ancora bisogno del supporto RTL. Il fatto che un'app non possa cambiare la direzione del layout nella stessa sessione risolve facilmente questo problema.

Detto questo, è piuttosto semplice.

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

6

Modo di estensione

Utilizzo dell'estensione per impostare l'immagine sul lato destro con offset personalizzato

   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

Swift -Estendi UiButton e metti queste linee

    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

Basandoti sull'elegante soluzione di Piotr Tomasik: se vuoi avere un po 'di spazio tra l'etichetta del pulsante e anche l'immagine , includi quello nel tuo bordo inserendo come segue (copiando il mio codice qui che funziona perfettamente per me):

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

Grazie Piotr per la tua soluzione!

Erik


@lulian: di recente ho usato la soluzione di Liau Jian Jie (la risposta accettata qui), che funziona alla grande ed è una soluzione molto elegante.
Erik van der Neut,

Ciò non funziona neanche per me poiché modifica l'allineamento del testo.
Iulian Onofrei,

3

Fai da solo. Xcode10, swift4,

Per la progettazione a livello di interfaccia utente

inserisci qui la descrizione dell'immagine

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

I valori dell'inserzione del bordo vengono applicati a un rettangolo per ridurre o espandere l'area rappresentata da quel rettangolo. In genere, gli inserti dei bordi vengono utilizzati durante il layout della vista per modificare il riquadro della vista. Valori positivi fanno sì che il frame sia inserito (o ridotto) della quantità specificata. I valori negativi causano l'inizio (o l'espansione) del frame della quantità specificata.

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 )

    }
}

per la progettazione dell'interfaccia utente di StoryBoard

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


c'è un modo per renderlo più elegante?
Zaporozhchenko Oleksandr,


2

Prese la risposta di @ Piotr e la trasformò in un'estensione Swift. Assicurati di impostare l'immagine e il titolo prima di chiamarlo, in modo che le dimensioni del pulsante siano corrette.

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

Un'opzione rapida che fa quello che vuoi senza giocare con nessun inserto:

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
    }

}

1

Le soluzioni qui menzionate hanno smesso di funzionare una volta abilitato il layout automatico . Ho dovuto inventare il mio:

Sottoclasse UIButton e layoutSubviewsmetodo override :

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

}

Risultato:

inserisci qui la descrizione dell'immagine


1

rapida soluzione di migrazione 3.0 fornita da 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
        }

1

Ho deciso di non utilizzare la vista immagine pulsante standard perché le soluzioni proposte per spostarlo sembravano confuse. Questo mi ha procurato l'estetica desiderata ed è intuitivo riposizionare il pulsante modificando i vincoli:

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

pulsante con la freccia destra


Questo non risponde ai tocchi, il testo si attenua ma l'immagine no
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
}

0

Che ne dici di Vincoli? A differenza di semanticContentAttribute, non cambiano la semantica. Qualcosa del genere forse:

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

o nell'Obiettivo-C:

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

Avvertenze: non testato, iOS 9+


0

Per allineare l'immagine a destra all'interno di UIButton, prova sotto il codice

btn.contentHorizontalAlignment = .right

Questo non è ciò di cui l'autore ha chiesto.
Mateusz,

0

Dopo aver provato più soluzioni da Internet, non stavo raggiungendo il requisito esatto. Così ho finito per scrivere un codice di utilità personalizzato. Pubblicare per aiutare qualcuno in futuro. Testato su rapido 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

per questo problema puoi creare UIView all'interno di "etichetta con UIImage view" e impostare la classe UIView come UIControl e creare IBAction come tuch up in side

inserisci qui la descrizione dell'immagine


0

Swift 4 e 5

Cambia la direzione dell'immagine del pulsante UIB (RTL e 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)
    }
}

Cosa Utility?
Byron Coetsee,

Ho appena rimosso l'utilità, è una classe nel mio codice in cui posso verificare se la lingua selezionata è l'arabo o l'inglese
Rashid Latif

0

Xcode 11.4 Swift 5.2

Per chiunque cerchi di rispecchiare lo stile del pulsante Indietro con il gallone in questo modo:

inserisci qui la descrizione dell'immagine

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

Implementazione:

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

@objc func nextTapped() {
    // your code
}

0

Ho finito per creare un pulsante personalizzato, che consente di impostare l'immagine da Inspector. Di seguito è il mio codice:

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

Puoi regolare il valore dell'imbottitura degli spazi vuoti da Impostazioni per regolare la spaziatura tra il testo e l'immagine.

PS: ho usato parte del codice dalla risposta di @Mark Hennings

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.