Comment placer l'image sur le côté droit du texte dans un bouton UIB?

300

Je ne veux pas utiliser une sous-vue si je peux l'éviter. Je veux un UIButtonavec une image d'arrière-plan, du texte et une image. En ce moment, quand je fais cela, l'image est sur le côté gauche du texte. L'image d'arrière-plan, le texte et l'image ont tous des états de surbrillance différents.

jasongregori
la source
Pour ajouter un autre "hack" à la liste croissante ici: vous pouvez définir le titre attribué du bouton à une chaîne attribuée contenant le titre de votre bouton + un espace + l'image (en tant que NSTextAttachment). Vous devrez peut-être modifier les limites de la pièce jointe pour l'aligner comme vous le souhaitez (voir stackoverflow.com/questions/26105803/… ).
Manav

Réponses:

266

Bien que certaines des réponses suggérées soient très créatives et extrêmement intelligentes, la solution la plus simple est la suivante:

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

Aussi simple que cela. En prime, l'image sera sur le côté gauche dans les endroits de droite à gauche.

EDIT : comme la question a été posée plusieurs fois, il s'agit d' iOS 9 + .

Benjamin
la source
89
Je ne peux pas croire que cette réponse ait été acceptée. Personne ne fait de localisation pour leurs applications?
Zoltán
6
@pallzoltan: cela répond à la question (c'est-à-dire "Comment puis-je mettre l'image sur le côté droit du texte dans un UIButton?"). Qu'est-ce que la localisation a à voir avec cela?
Benjamin
17
Il n'y a pas beaucoup de situations où vous ne voulez pas que votre mise en page soit "retournée" dans les langues RTL. La configuration directe semanticContentAttributen'est qu'un hack / contournement, pas une vraie solution.
Zoltán
6
Mon approche est que vous ne savez pas ce que la personne qui pose la question est en train de construire, donc il vaut toujours mieux compter avec une flexibilité pour la mise en page.
Zoltán
2
La localisation de @ Zoltán n'est pas un problème, il suffit d'inverser la propriété en fonction des paramètres régionaux actuels.
manmal
561

Solution la plus simple:

iOS 10 et plus, 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)

Avant 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
la source
8
J'ai utilisé cela pour la vue du titre de la barre de navigation et il y avait un problème. C'est bien quand il est chargé pour la première fois, mais lorsque vous poussez un contrôleur de vue et le faites éclater, le titre est inversé.
funct7
@WoominJoshPark Intéressant ... Je peux seulement deviner que c'est parce que la transformation est animée en interne pour les animations pop de navigation.
Liau Jian Jie
1
J'ai trouvé que si cela causait des plaintes concernant les conflits de contraintes de mise en page automatique au moment de l'exécution, il pouvait être corrigé en ajoutant ceci dans layoutSubviews ()
Vlad
1
Comment puis-je mettre plus d'espace entre le texte et l'image?
rohinb
2
@rohinb @ jose920405 Essayez de définir ImageEdgeInsets et ContentEdgeInsets pour le remplissage (en gardant à l'esprit qu'ils ont été inversés). Par exemple button.ImageEdgeInsets = new UIEdgeInsets(0, -leftPadding, 0, leftPadding); button.ContentEdgeInsets = new UIEdgeInsets(0, 0, 0, leftPadding);. C'est dans Xamarin, mais devrait se traduire assez facilement en Swift / Obj-C.
Lee Richardson
269

MIS À JOUR POUR XCODE 9 (Via Interface Builder)

Il existe un moyen plus simple à partir du générateur d'interface .

Sélectionnez le bouton UIB et sélectionnez cette option dans Afficher les utilitaires> Sémantique :

de gauche à droite entrez la description de l'image ici C'est tout! Agréable et simple!

FACULTATIF - 2e étape:

Si vous souhaitez ajuster l'espacement entre l'image et le titre, vous pouvez modifier l' encart d'image ici:

entrez la description de l'image ici

J'espère que cela pourra aider!

Victor Rius
la source
2
Dans Xcode 9.0 beta 5 (9M202q), vous ne voyez malheureusement le résultat qu'à l'exécution - dans le storyboard, il montre toujours l'image à gauche. Notez également qu'à cause de cela, il faut des essais et des erreurs pour définir les encarts corrects.
PDK
3
Veuillez ne pas le faire de cette façon - cela interrompt la localisation pour les langues de droite à gauche.
jsadler
169

Le sous-classement UIButton est totalement inutile. Au lieu de cela, vous pouvez simplement définir une valeur d'encart gauche élevée pour les encarts d'image et une petite encart de droite pour le titre. Quelque chose comme ça:

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
la source
3
Cela a fonctionné, mais rappelez-vous qu'aujourd'hui avec la mise en page automatique, vous devez le faire sur viewDidAppear et non sur viewDidLoad
Hola Soy Edu Feliz Navidad
91

Je donne à Inspire48 le mérite de celui-ci. Sur la base de sa suggestion et en regardant cette autre question, je suis venu avec cela. Sous-classe UIButton et remplacez ces méthodes.

@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
la source
3
UIButton est un cluster de classes et ne doit pas être sous-classé.
Scott Berrevoets
50
Ce n'est pas vrai, la documentation mentionne explicitement le sous-classement et fournit des méthodes que vous devez remplacer pour un comportement de disposition personnalisé.
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 et les backgroundRectForBoundssous-classes qui fournissent des ornements d'arrière-plan personnalisés peuvent remplacer cette méthode et renvoyer un rectangle de limites modifié pour empêcher le bouton de dessiner sur tout contenu personnalisé. » méthodes, mais je suppose qu'ils ne se soucient pas des sous-classes.
christophercotton
1
On dirait que cette formule est meilleure pour mettre en miroir le cadre d'image: frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left - frame.origin.x;Cela fonctionne mieux pour UIControlContentHorizontalAlignmentCenteret pour les autres ...
k06a
@ GwendalRoué Ce n'est pas parce qu'il est plus court qu'il vaut mieux. C'est un moyen plus piraté, et cela fait que le bouton ignore les encarts réels, et peut casser dans les langues de droite à gauche. Avec cette réponse, vous avez le plein contrôle de la mise en page
Accatyyc
76

Mettez simplement à jour les encarts lorsque le titre est modifié. Vous devez compenser l'encart avec un encart égal et opposé de l'autre côté.

[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
la source
3
Vous voudrez peut-être ajouter [thebutton.titleLabel sizeToFit];avant. La largeur peut être nulle si vous n'avez pas déclenché de mise en page. Il en va de même pour la taille de l'image (utilisez simplement la taille UIImage.size au lieu de la taille imageView)
delrox
@delrox bon point. Peut utiliser titleWidth = [self.titleLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, self.bounds.size.height)].width;(ou si vous êtes préoccupé par le fait que le cadre du bouton n'est pas encore établi, utilisez également CGFLOAT_MAX pour la hauteur) etimageWidth = self.currentImage.size.width;
Dave Goldman
1
Fonctionne parfaitement sur viewDidLayoutSubviews
Gwendal Roué
J'ai dû placer cela dans layoutSubviewsma UITableViewCellsous - classe mais ça marche bien. Merci!
RyanG
60

Toutes ces réponses, en date de janvier 2016, sont inutiles. Dans Interface Builder, définissez la vue sémantique sur Force Right-to-Left, ou si vous préférez la méthode de programmation, semanticContentAttribute = .forceRightToLeftcela fera apparaître l'image à droite de votre texte.

barndog
la source
5
Malheureusement, il ne prend pas en charge les versions antérieures à 9. Encore une bonne réponse, tho.
Eddie
1
Je suis triste de signaler que le fait de définir cela sur un UIButton qui est ensuite utilisé pour UIBarButtonItem n'a entraîné aucun changement.
Amelia
Comme @Amelia l'a mentionné, cela ne fonctionne pas si vous appelez UIBarButtonItem(customView: button), mais cela fonctionnera si vous placez le bouton dans une vue vide
tt.Kilew
@ tt.Kilew, en utilisant XCode 8.1, vous le faites fonctionner. J'ai défini uiButton.semanticContentAttribute = .forceRightToLeft et fourni let nextButton = UIBarButtonItem (customView: uiButton)
Eugene Biryukov
53

Dans le générateur d'interface, vous pouvez configurer les options Edge Insets pour UIButton, séparément chacune des trois parties: contenu, image, titre

entrez la description de l'image ici entrez la description de l'image ici

Xcode 8:

entrez la description de l'image ici

Gennadiy Ryabkin
la source
3
en fait la meilleure réponse à mon avis ce stackoverflow.com/a/39013315/1470374 ))
Gennadiy Ryabkin
25

Mise à jour: 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
    }
}

Réponse originale pour Swift 2:

Une solution qui gère tous les alignements horizontaux, avec un exemple d'implémentation Swift. Traduisez simplement en Objective-C si nécessaire.

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

Il convient également de noter qu'il gère assez bien les encarts d'image et de titre.

Inspiré de la réponse jasongregori;)

Jean-Baptiste
la source
1
Cette solution a fonctionné pour moi, mais mon image avait besoin d'espace autour d'elle, j'ai donc ajouté le code suivant: self.contentEdgeInsets = UIEdgeInsetsMake (10.0, 10.0, 10.0, 10.0)
user1354603
1
J'aime cette façon parce que vous pouvez ajouter @IBDesignableà la classe et la voir inversée au moment du design.
James Toomey
Je préfère cette solution car elle fonctionne même lorsqu'elle est placée dans la barre de navigation.
El Horrible
10

Si cela doit être fait dans UIBarButtonItem , un habillage supplémentaire en vue doit être utilisé.
Cela fonctionnera

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)

Ça ne marchera pas

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
la source
7

Voici une solution pour le UIButtoncontenu aligné au centre. Ce code rend l'image alignée à droite et permet d'utiliser imageEdgeInsetset titleEdgeInsetspour un positionnement précieux.

entrez la description de l'image ici

Sous-classe UIButtonavec votre classe personnalisée et ajoutez:

- (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
la source
1
Vous pouvez également ajouter IBDESIGNABLE à l'en-tête de classe pour le voir dans le storyborad yadi.sk/i/fd6Si-BJqzCFD
Nikolay Shubenkov
6

Étant donné que la solution de transformation ne fonctionne pas dans iOS 11, j'ai décidé d'écrire une nouvelle approche.

Réglage des boutons semanticContentAttribute nous donne l'image bien à droite sans avoir à relayer si le texte change. Pour cette raison, c'est la solution idéale. Cependant, j'ai toujours besoin du support RTL. Le fait qu'une application ne puisse pas changer son sens de mise en page dans la même session résout facilement ce problème.

Cela dit, c'est assez simple.

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

Voie d'extension

Utiliser l'extension pour définir l'image sur le côté droit avec un décalage personnalisé

   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
la source
4

Swift -Extend the UiButton et mettez ces lignes

    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
la source
3

S'appuyant sur la solution élégante de Piotr Tomasik: si vous souhaitez également avoir un peu d' espacement entre l'étiquette du bouton et l'image , incluez-la dans vos encarts de bord comme suit (en copiant mon code ici qui fonctionne parfaitement pour moi):

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

Merci Piotr pour votre solution!

Erik

Erik van der Neut
la source
@lulian: J'ai utilisé la solution de Liau Jian Jie à la place récemment (la réponse acceptée ici), et cela fonctionne avec brio et est une solution très élégante.
Erik van der Neut
Cela ne fonctionne pas non plus pour moi car cela modifie l'alignement du texte.
Iulian Onofrei
3

Faites-vous. Xcode10, swift4,

Pour la conception d'interface utilisateur par programmation

entrez la description de l'image ici

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

Les valeurs d'encart de bord sont appliquées à un rectangle pour réduire ou agrandir la zone représentée par ce rectangle. En règle générale, les encarts de bord sont utilisés lors de la présentation de la vue pour modifier le cadre de la vue. Les valeurs positives entraînent l'insertion (ou la réduction) du cadre de la quantité spécifiée. Les valeurs négatives entraînent le décalage (ou le développement) du cadre de la quantité spécifiée.

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 )

    }
}

pour la conception de l'interface utilisateur de StoryBoard

entrez la description de l'image ici entrez la description de l'image ici

Nazmul Hasan
la source
existe-t-il un moyen de le rendre plus élégant?
Zaporozhchenko Oleksandr
2

Sous-classement et disposition dominante Les sous-vues sont probablement votre meilleure solution.

Référencé depuis: iPhone UIButton - position de l'image

FeifanZ
la source
3
Il n'y a absolument aucun problème à sous-classer UIButton.
2013
2

A pris la réponse de @ Piotr et en a fait une extension Swift. Assurez-vous de définir l'image et le titre avant d'appeler cela, afin que le bouton taille correctement.

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
la source
2

Une option rapide qui fait ce que vous voulez sans jouer avec des encarts:

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
la source
1

Les solutions mentionnées ici ont cessé de fonctionner, une fois que j'ai activé la disposition automatique . Je devais trouver le mien:

Sous-classe UIButton et layoutSubviewsméthode de remplacement :

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

}

Résultat:

entrez la description de l'image ici

Lukasz
la source
1

swift 3.0 Migration solution proposée par 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
la source
1

J'ai décidé de ne pas utiliser la vue d'image de bouton standard car les solutions proposées pour le déplacer semblaient floues. Cela m'a donné l'esthétique souhaitée, et il est intuitif de repositionner le bouton en changeant les contraintes:

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

bouton avec flèche droite

Mark Hennings
la source
Cela ne répond pas aux tapotements, le texte s'assombrit mais l'image ne le fait pas
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
la source
0

Et les contraintes? Contrairement à semanticContentAttribute, ils ne changent pas la sémantique. Quelque chose comme ça peut-être:

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

ou en Objectif-C:

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

Mises en garde: non testé, iOS 9+

rockworkhouse
la source
0

Pour aligner à droite l'image dans UIButton, essayez le code ci-dessous

btn.contentHorizontalAlignment = .right
Dhaval H. Nena
la source
Ce n'est pas ce que l'auteur a demandé.
Mateusz
0

Après avoir essayé plusieurs solutions sur Internet, je n'atteignais pas l'exigence exacte. J'ai donc fini par écrire du code utilitaire personnalisé. Affichage pour aider quelqu'un à l'avenir. Testé sur 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)
    }
jeet.chanchawat
la source
0

pour ce problème, vous pouvez créer UIView à l'intérieur de "étiquette avec vue UIImage" et définir la classe UIView comme UIControl et créer IBAction comme tuch up in side

entrez la description de l'image ici

Sushil Vyas
la source
0

Swift 4 et 5

Changer la direction de l'image UIButton (RTL et 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
la source
Quoi Utility?
Byron Coetsee le
Je viens de supprimer l'utilitaire, c'est une classe dans mon code où je peux vérifier si la langue sélectionnée est l'arabe ou l'anglais
Rashid Latif
0

Xcode 11.4 Swift 5.2

Pour ceux qui essaient de refléter le style du bouton Retour avec le chevron comme ceci:

entrez la description de l'image ici

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

La mise en oeuvre:

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

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

J'ai fini par créer un bouton personnalisé, qui permet de définir l'image à partir de l'inspecteur. Voici mon 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)
            ])
        }
    }
}

Vous pouvez ajuster la valeur du remplissage de l'espace à partir de l'inspecteur pour ajuster l'espacement entre le texte et l'image.

PS: utilisé une partie de code de la réponse @Mark Hennings

Mahendra Liya
la source