Comment mettre l'image sur le côté droit du texte dans un UIButton?

Je ne veux pas utiliser un subview si je peux l'éviter. Je veux un UIButton avec une image d'arrière-plan, du texte et une image. Maintenant, quand je fais ça, l'image est sur le côté gauche du texte. L'image de fond, le texte et l'image ont tous des états de surlignage différents.

222
demandé sur Super Chafouin 2011-08-18 04:06:29
la source

24 ответов

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 ça. En prime, l'image sera à gauche dans les locales de droite à gauche.

EDIT : comme la question a été posée plusieurs fois, c'est iOS 9 + .

162
répondu Benjamin 2018-07-06 11:26:04
la source

solution la plus simple:

iOS 10 & up, 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);
469
répondu Liau Jian Jie 2017-03-27 18:19:19
la source

sous-classement UIButton est complètement inutile. Au lieu de cela, vous pouvez simplement définir une valeur élevée à gauche pour les insets d'image, et un petit inset à droite pour le titre. Quelque chose comme ceci:

button.imageEdgeInsets = UIEdgeInsetsMake(0., button.frame.size.width - (image.size.width + 15.), 0., 0.);
button.titleEdgeInsets = UIEdgeInsetsMake(0., 0., 0., image.size.width);
163
répondu Ben Baron 2013-10-05 00:48:45
la source

mise à jour pour XCODE 9 (Via Interface Builder)

il y a un moyen plus simple du Interface Builder . Sélectionnez L'UIButton et sélectionnez cette option dans la vue Utilities :

enter image description here

C'est ça! Simple et sympathique!

facultatif - 2e étape:

si vous voulez régler l'espacement entre l'image et le titre, vous pouvez changer le Inset D'Image ici:

enter image description here

Espère que ça aide!

162
répondu Victor Rius 2017-12-31 00:07:38
la source

je suis en train de faire Inspire48 le crédit pour cela. En me basant sur sa suggestion et en regardant cette autre question, j'ai trouvé ceci. Sous-classe UIButton et outrepasser 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
85
répondu jasongregori 2017-05-23 14:55:00
la source

il suffit de mettre à jour les insets lorsque le titre est modifié. Vous devez compenser pour le filet avec un filet é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);
72
répondu Piotr Tomasik 2013-11-15 08:06:14
la source

toutes ces réponses, en date de janvier 2016, sont inutiles. Dans Interface Builder, définissez la sémantique de la vue à Force Right-to-Left , ou si vous préférez la manière programmatique, semanticContentAttribute = .forceRightToLeft qui fera apparaître l'image à droite de votre texte.

59
répondu barndog 2016-08-23 19:03:19
la source

dans interface builder vous pouvez configurer les options Edge Insets pour UIButton, séparément chacune de trois parties: le contenu, l'image, le titre

enter image description here enter image description here

Xcode 8:

enter image description here

49
répondu zest 2016-10-08 14:53:31
la source

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 de mise en œuvre Swift. Traduisez vers L'Objectif-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
    }
}

vaut également la peine de noter qu'il gère assez bien l'image et le titre insets.

Inspiré partir de jasongregori réponse ;)

22
répondu Jean-Baptiste 2016-10-19 17:10:40
la source

Voici la solution pour UIButton avec un contenu aligné sur le centre. Ce code rend l'image alignée à droite et permet d'utiliser imageEdgeInsets et titleEdgeInsets pour le positionnement précieux.

enter image description here

sous-classe UIButton avec votre classe personnalisée et ajouter:

- (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;
}
6
répondu Vitaliy Gozhenko 2015-10-30 04:12:01
la source

si cela doit être fait dans UIBarButtonItem , l'emballage 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)

Cela 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)
5
répondu tt.Kilew 2017-04-12 11:51:54
la source

construit sur la solution élégante de Piotr Tomasik: si vous voulez avoir un peu de espacement entre l'étiquette de bouton et l'image aussi, alors inclure que dans vos insets de bord comme suit (copier 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

3
répondu Erik van der Neut 2015-12-08 03:40:42
la source

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

ajuster les boutons semanticContentAttribute nous donne l'image bien à droite sans avoir à relayout si le texte change. De ce fait, il est la solution idéale. Cependant, j'ai encore besoin du soutien de RTL. Le fait qu'une application ne puisse pas changer sa direction de mise en page dans la même session résout ce problème facilement.

avec ça dit, c'est joli tout droit vers l'avant.

extension UIButton {
    func alignImageRight() {
        if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
            semanticContentAttribute = .forceRightToLeft
        }
        else {
            semanticContentAttribute = .forceLeftToRight
        }
    }
}
3
répondu cnotethegr8 2018-05-22 16:02:05
la source

a pris la réponse de @Piotr et en a fait une extension rapide. Assurez-vous de définir l'image et le titre avant d'appeler ceci, de sorte que les tailles de bouton 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)
    }
}

}

2
répondu Nick Yap 2015-08-10 19:50:41
la source

une option swift qui fait ce que vous voulez sans jouer avec des insets:

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
répondu Chris 2015-09-01 04:27:03
la source

sous-classement et au mépris de layoutSubviews est probablement votre meilleure façon d'aller.

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

1
répondu FeifanZ 2017-05-23 15:18:24
la source

Swift-étendre L'UiButton et mettre 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);
    }
1
répondu Pramod 2018-04-08 05:54:36
la source
Les Solutions

mentionnées ici ont cessé de fonctionner, dès que j'ai activé Auto Layout . J'ai dû trouver la mienne:

sous-classe UIButton and override layoutSubviews méthode:

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

enter image description here

0
répondu Lukasz 2015-11-19 12:23:41
la source

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
répondu Alexander Volkov 2016-09-18 23:00:32
la source

swift 3.0 Migration solution donné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
        }
0
répondu Sourabh Sharma 2016-10-05 12:32:18
la source

Qu'en est-il des contraintes? Contrairement à semanticcontententattribute, ils ne changent pas la sémantique. Quelque chose comme ceci peut-être:

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

ou dans L'objectif C:

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

mises en garde: non testé, iOS 9+

0
répondu rock workinghouse 2017-08-03 14:55:38
la source

à droite alignez l'image dans UIButton essayez le code ci-dessous

btn.contentHorizontalAlignment = .right
0
répondu Dhaval H. Nena 2018-08-21 08:08:11
la source

merci à Vitaliy Gozhenko

je veux juste ajouter que vous pouvez ajouter IB_DESIGNABLE avant votre bouton @interface et régler votre classe de bouton dans storyborad. Ensuite, vous pouvez regarder la mise en page en temps réel sans le lancement de l'application juste à l'étape de la construction de l'interface

enter image description here

-1
répondu Nikolay Shubenkov 2017-05-23 15:26:38
la source

la bonne réponse dans Swift

import UIKit

extension UIButton {

     func imageRectForContentRect(contentRect:CGRect) -> CGRect {
        var frame = self.imageRectForContentRect(contentRect)
        frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left

        return frame
    }

    func titleRectForContentRect(contentRect:CGRect) -> CGRect {
        var frame = self.titleRectForContentRect(contentRect)
        frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(self.imageRectForContentRect(contentRect))
        return frame
    }
}
-4
répondu Xristos Hadjikyriacou 2015-07-27 08:06:29
la source

Autres questions sur ios user-interface