¿Cómo coloco la imagen en el lado derecho del texto en un UIButton?

300

No quiero usar una subvista si puedo evitarla. Quiero un UIButtoncon una imagen de fondo, texto y una imagen en él. En este momento, cuando hago eso, la imagen está en el lado izquierdo del texto. La imagen de fondo, el texto y la imagen tienen estados de resaltado diferentes.

jasongregori
fuente
Para agregar otro "hack" a la creciente lista aquí: puede establecer el atributo atribuido del botón en una cadena atribuida que contenga el título del botón + un espacio + la imagen (como un NSTextAttachment). Es posible que deba ajustar los límites del archivo adjunto para que se alinee como desee (consulte stackoverflow.com/questions/26105803/… ).
Manav

Respuestas:

266

A pesar de que algunas de las respuestas sugeridas son muy creativas y extremadamente inteligentes, la solución más simple es la siguiente:

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

Tan sencillo como eso. Como beneficio adicional, la imagen estará en el lado izquierdo en configuraciones regionales de derecha a izquierda.

EDITAR : como se ha hecho la pregunta varias veces, este es iOS 9+ .

Benjamín
fuente
89
No puedo creer que esta respuesta haya sido aceptada. ¿Nadie hace localizaciones para sus aplicaciones?
Zoltán
66
@pallzoltan: esto responde a la pregunta (es decir, "¿Cómo coloco la imagen en el lado derecho del texto en un UIButton?"). ¿Qué tiene que ver la localización con esto?
Benjamin
17
No hay muchas situaciones en las que no desee que su diseño se "voltee" en lenguajes RTL. La configuración directa semanticContentAttributees solo un truco / solución alternativa, no una solución real.
Zoltán
66
Mi enfoque es que no sabes qué está construyendo la persona que hace la pregunta, por lo que siempre es mejor contar con flexibilidad para el diseño.
Zoltán
2
La localización de @ Zoltán no es un problema, solo invierta la propiedad dependiendo de la ubicación actual.
manmal
561

La solución más simple:

iOS 10 y superior, 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)

Antes de 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
fuente
8
Utilicé esto para la vista del título de la barra de navegación y hubo un error. Está bien cuando se carga por primera vez, pero cuando presiona un controlador de vista y lo abre, el título se voltea.
funct7
@WoominJoshPark Interesante ... Solo puedo suponer que esto se debe a que la transformación está animada internamente para animaciones pop de navegación.
Liau Jian Jie
1
Encontré que si esto está causando quejas sobre conflictos de restricción de autolimpieza en tiempo de ejecución, se puede solucionar agregando esto en layoutSubviews ()
Vlad
1
¿Cómo puedo poner más espacio entre el texto y la imagen?
rohinb
2
@rohinb @ jose920405 Intente configurar ImageEdgeInsets y ContentEdgeInsets para el relleno (teniendo en cuenta que se han invertido). Por ejemplo button.ImageEdgeInsets = new UIEdgeInsets(0, -leftPadding, 0, leftPadding); button.ContentEdgeInsets = new UIEdgeInsets(0, 0, 0, leftPadding);. Eso está en Xamarin, pero debería traducirse a Swift / Obj-C fácilmente.
Lee Richardson
269

ACTUALIZADO PARA XCODE 9 (Vía Interface Builder)

Hay una manera más fácil del Creador de interfaces .

Seleccione el botón UIB y seleccione esta opción en Ver utilidades> Semántica :

de izquierda a derecha ingrese la descripción de la imagen aquí ¡Eso es! Agradable y simple!

OPCIONAL - 2do paso:

Si desea ajustar el espacio entre la imagen y el título, puede cambiar el recuadro de imagen aquí:

ingrese la descripción de la imagen aquí

¡Espero que ayude!

Victor Rius
fuente
2
En Xcode 9.0 beta 5 (9M202q), desafortunadamente solo se ve el resultado en tiempo de ejecución; en el guión gráfico todavía se muestra la imagen a la izquierda. También tenga en cuenta que, debido a esto, se requieren pruebas y errores para configurar las inserciones correctas.
PDK
3
No lo haga de esta manera: esto rompe la localización de los idiomas de derecha a izquierda.
jsadler
169

Subclasificar UIButton es completamente innecesario. En su lugar, simplemente puede establecer un valor de inserción izquierdo alto para las inserciones de imagen y un pequeño recuadro derecho para el título. Algo como esto:

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
fuente
3
Funcionó, pero solo recuerda que hoy con autolayout tienes que hacerlo en viewDidAppear y no en viewDidLoad
Hola Soy Edu Feliz Navidad
91

Le doy crédito a Inspire48 por este. Basado en su sugerencia y mirando esa otra pregunta, se me ocurrió esto. Subclase UIButton y anular estos métodos.

@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
fuente
3
UIButton es un grupo de clases y no debe subclasificarse.
Scott Berrevoets
50
Eso no es cierto, la documentación menciona explícitamente las subclases y proporciona métodos que debe anular para un comportamiento de diseño personalizado.
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 y las backgroundRectForBoundssubclases que proporcionan adornos de fondo personalizados pueden anular este método y devolver un rectángulo de límites modificado para evitar que el botón dibuje sobre cualquier contenido personalizado '. Ninguno menciona esos específicos métodos, pero supongo que no les importan las subclases.
christophercotton
1
Parece que esta fórmula es mejor para reflejar el marco de la imagen: frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left - frame.origin.x;funciona mejor para UIControlContentHorizontalAlignmentCentery para otros ...
k06a
@ GwendalRoué El hecho de que sea más corto no significa que sea mejor. Es una forma más complicada, y hace que el botón ignore las inserciones reales, y puede romperse en idiomas de derecha a izquierda. Con esta respuesta, usted tiene el control total del diseño
Accatyyc
76

Simplemente actualice las inserciones cuando se cambie el título. Debe compensar el recuadro con un recuadro igual y opuesto en el otro lado.

[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
fuente
3
Es posible que desee agregar [thebutton.titleLabel sizeToFit];antes. El ancho puede ser cero si no ha activado un diseño. Lo mismo ocurre con el tamaño de la imagen (solo use UIImage.size en lugar del tamaño de imageView)
delrox
@delrox buen punto. Puede usar titleWidth = [self.titleLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, self.bounds.size.height)].width;(o si le preocupa que el marco del botón aún no se haya establecido, use CGFLOAT_MAX también para la altura) yimageWidth = self.currentImage.size.width;
Dave Goldman el
1
Funciona perfectamente en viewDidLayoutSubviews
Gwendal Roué
Tuve que colocar esto layoutSubviewsen mi UITableViewCellsubclase, pero está funcionando bien. ¡Gracias!
RyanG
60

Todas estas respuestas, a partir de enero de 2016, son innecesarias. En Interface Builder, configure View Semantic en Force Right-to-Left, o si lo prefiere de forma programática, semanticContentAttribute = .forceRightToLefteso hará que la imagen aparezca a la derecha de su texto.

barndog
fuente
55
Lamentablemente no es compatible con ios mayores de 9. Aún así, buena respuesta, aunque.
Eddie
1
Me entristece informar que establecer esto en un UIButton que luego se usa para UIBarButtonItem no produjo ningún cambio.
Amelia
Como mencionó @Amelia, no funciona si llamas UIBarButtonItem(customView: button), pero funcionará si envuelves el botón dentro de una vista vacía
tt.Kilew
@ tt.Kilew, usando XCode 8.1 lo haces funcionar. Configuré uiButton.semanticContentAttribute = .forceRightToLeft y proporcioné let nextButton = UIBarButtonItem (customView: uiButton)
Eugene Biryukov
53

En el generador de interfaces, puede configurar las opciones Edge Insets para UIButton, por separado cada una de las tres partes: contenido, imagen, título

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Xcode 8:

ingrese la descripción de la imagen aquí

Gennadiy Ryabkin
fuente
3
En realidad, la mejor respuesta desde mi punto de vista este stackoverflow.com/a/39013315/1470374 ))
Gennadiy Ryabkin
25

Actualización: 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
    }
}

Respuesta original para Swift 2:

Una solución que maneja todas las alineaciones horizontales, con un ejemplo de implementación Swift. Simplemente traduzca a Objective-C si es necesario.

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

También vale la pena señalar que maneja bastante bien las inserciones de imagen y título.

Inspirado en la respuesta jasongregori;)

Jean-Baptiste
fuente
1
Esta solución funcionó para mí, sin embargo, mi imagen necesitaba algo de espacio alrededor, así que agregué el siguiente código: self.contentEdgeInsets = UIEdgeInsetsMake (10.0, 10.0, 10.0, 10.0)
user1354603
1
Me gusta de esta manera porque puedes agregar @IBDesignablea la clase y verla volteada en tiempo de diseño.
James Toomey el
Prefiero esta solución porque incluso funciona cuando se coloca en la barra de navegación.
El horrible
10

Si esto debe hacerse en UIBarButtonItem , se debe usar un ajuste adicional a la vista
Esto funcionará

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)

Esto no va a funcionar

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

Aquí hay una solución para UIButtoncontenido alineado al centro. Este código hace que la imagen esté alineada a la derecha y permite su uso imageEdgeInsetsy titleEdgeInsetspara un posicionamiento precioso.

ingrese la descripción de la imagen aquí

Subclase UIButtoncon su clase personalizada y agregue:

- (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
fuente
1
También puede agregar IBDESIGNABLE al encabezado de la clase para verlo en el storyborad yadi.sk/i/fd6Si-BJqzCFD
Nikolay Shubenkov
6

Como la solución de transformación no funciona en iOS 11, decidí escribir un nuevo enfoque.

Ajuste de los botones semanticContentAttribute nos da la imagen muy bien a la derecha sin tener que retransmitir si el texto cambia. Por eso es la solución ideal. Sin embargo, todavía necesito soporte RTL. El hecho de que una aplicación no pueda cambiar su dirección de diseño en la misma sesión resuelve este problema fácilmente.

Dicho esto, es bastante sencillo.

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

Forma de extensión

Usando la extensión para establecer la imagen en el lado derecho con desplazamiento personalizado

   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
fuente
4

Swift - Extiende el UiButton y coloca estas líneas

    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
fuente
3

Basándose en la elegante solución de Piotr Tomasik: si desea tener un poco de espacio entre la etiqueta del botón y la imagen también, entonces inclúyalo en sus inserciones de borde de la siguiente manera (copiando mi código aquí que funciona perfectamente para mí):

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

¡Gracias Piotr por tu solución!

Erik

Erik van der Neut
fuente
@lulian: He estado usando la solución de Liau Jian Jie recientemente (la respuesta aceptada aquí), y eso funciona de manera brillante y es una solución muy elegante.
Erik van der Neut
Eso tampoco funciona para mí, ya que cambia la alineación del texto.
Iulian Onofrei
3

Hazlo tú mismo. Xcode10, swift4,

Para el diseño programático de la interfaz de usuario

ingrese la descripción de la imagen aquí

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

Los valores de inserción de borde se aplican a un rectángulo para reducir o expandir el área representada por ese rectángulo. Normalmente, las inserciones de borde se utilizan durante el diseño de la vista para modificar el marco de la vista. Los valores positivos hacen que el marco se inserte (o reduzca) en la cantidad especificada. Los valores negativos hacen que el marco se comience (o expanda) en la cantidad especificada.

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 )

    }
}

para el diseño de la interfaz de usuario de StoryBoard

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Nazmul Hasan
fuente
¿Hay alguna manera de hacerlo más elegante?
Zaporozhchenko Oleksandr
2

Subclases y diseño superior: las subvistas son probablemente la mejor opción.

Referenciado desde: iPhone UIButton - posición de la imagen

FeifanZ
fuente
3
No hay absolutamente ningún problema para la subclase UIButton.
no el
2

Tomó la respuesta de @ Piotr y la convirtió en una extensión Swift. Asegúrese de configurar la imagen y el título antes de llamar a esto, para que el botón se ajuste correctamente.

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
fuente
2

Una opción rápida que hace lo que quieres sin jugar con inserciones:

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
fuente
1

Las soluciones mencionadas aquí dejaron de funcionar, una vez que habilité el diseño automático . Tuve que inventar el mío:

Subclase UIButton y layoutSubviewsmétodo de anulación :

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

}

Resultado:

ingrese la descripción de la imagen aquí

Lukasz
fuente
1

Solución de migración swift 3.0 dada por 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
fuente
1

Decidí no usar la vista de imagen de botón estándar porque las soluciones propuestas para moverlo se sentían extrañas. Esto me dio la estética deseada, y es intuitivo reposicionar el botón cambiando las restricciones:

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

botón con flecha derecha

Mark Hennings
fuente
Esto no responde a los toques, el texto se atenúa pero la imagen 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
}
Alexander Volkov
fuente
0

¿Qué hay de las restricciones? A diferencia de semanticContentAttribute, no cambian la semántica. Algo como esto quizás:

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

o en Objective-C:

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

Advertencias: no probado, iOS 9+

casa de trabajo de roca
fuente
0

Para alinear la imagen a la derecha dentro de UIButton, intente debajo del código

btn.contentHorizontalAlignment = .right
Dhaval H. Nena
fuente
Esto no es lo que el autor preguntó.
Mateusz
0

Después de probar varias soluciones en Internet, no estaba logrando el requisito exacto. Así que terminé escribiendo código de utilidad personalizado. Publicar para ayudar a alguien en el futuro. Probado en 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
fuente
0

para este problema, puede crear UIView dentro de "etiqueta con vista UIImage" y establecer la clase UIView como UIControl y crear IBAction como una protección lateral

ingrese la descripción de la imagen aquí

Sushil Vyas
fuente
0

Swift 4 y 5

Cambiar la dirección de la imagen UIButton (RTL y 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)
    }
}
Latif Rashid
fuente
¿Qué es Utility?
Byron Coetsee
Solo elimino la Utilidad, es una clase en mi código donde puedo verificar si el idioma seleccionado es árabe o inglés
Rashid Latif
0

Xcode 11.4 Swift 5.2

Para cualquiera que intente reflejar el estilo del botón Atrás con el galón como este:

ingrese la descripción de la imagen aquí

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

Implementación:

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

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

Terminé creando un botón personalizado, que permite configurar la imagen del inspector. Abajo está mi código:

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

Puede ajustar el valor de Gap Padding desde Inspector para ajustar el espacio entre el texto y la imagen.

PD: Utilicé parte del código de la respuesta de @Mark Hennings

Mahendra Liya
fuente