Swift - UIButton con dos líneas de texto

93

Me preguntaba si es posible crear un UIButton con dos líneas de texto. Necesito que cada línea tenga un tamaño de fuente diferente. La primera línea será de 17 puntos y la segunda de 11 puntos. Intenté jugar con poner dos etiquetas dentro de un UIButton, pero no puedo hacer que permanezcan dentro de los límites del botón.

Estoy intentando hacer todo esto en el generador de interfaz de usuario y no mediante programación.

Gracias

Scott
fuente

Respuestas:

249

Hay dos preguntas.

Me preguntaba si es posible crear un UIButton con dos líneas de texto

Esto es posible mediante el uso del guión gráfico o mediante programación.

Guión gráfico:

Cambiar el 'Modo de línea Break' de Carácter Wrap o Ajuste de línea y utilizar Alt / Opción + Enter tecla para introducir una nueva línea en el campo Título de la UIButton.

ingrese la descripción de la imagen aquí

Programáticamente:

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;
}

Necesito que cada línea tenga un tamaño de fuente diferente 1

El peor de los casos es que puede usar una UIButtonclase personalizada y agregar dos etiquetas dentro de ella.

La mejor forma es utilizar NSMutableAttributedString. Tenga en cuenta que esto se puede lograr solo mediante programación.

Rápido 5:

@IBOutlet weak var btnTwoLine: UIButton?

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    //applying the line break mode
    textResponseButton?.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
    let buttonText: NSString = "hello\nthere"

    //getting the range to separate the button title strings
    let newlineRange: NSRange = buttonText.range(of: "\n")

    //getting both substrings
    var substring1 = ""
    var substring2 = ""

    if(newlineRange.location != NSNotFound) {
        substring1 = buttonText.substring(to: newlineRange.location)
        substring2 = buttonText.substring(from: newlineRange.location)
    }

    //assigning diffrent fonts to both substrings
    let font1: UIFont = UIFont(name: "Arial", size: 17.0)!
    let attributes1 = [NSMutableAttributedString.Key.font: font1]
    let attrString1 = NSMutableAttributedString(string: substring1, attributes: attributes1)

    let font2: UIFont = UIFont(name: "Arial", size: 11.0)!
    let attributes2 = [NSMutableAttributedString.Key.font: font2]
    let attrString2 = NSMutableAttributedString(string: substring2, attributes: attributes2)

    //appending both attributed strings
    attrString1.append(attrString2)

    //assigning the resultant attributed strings to the button
    textResponseButton?.setAttributedTitle(attrString1, for: [])
}

Swift mayor

@IBOutlet weak var btnTwoLine: UIButton?

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        //applying the line break mode
        btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;

        var buttonText: NSString = "hello\nthere"

        //getting the range to separate the button title strings
        var newlineRange: NSRange = buttonText.rangeOfString("\n")

        //getting both substrings
        var substring1: NSString = ""
        var substring2: NSString = ""

        if(newlineRange.location != NSNotFound) {
            substring1 = buttonText.substringToIndex(newlineRange.location)
            substring2 = buttonText.substringFromIndex(newlineRange.location)
        }

        //assigning diffrent fonts to both substrings
        let font:UIFont? = UIFont(name: "Arial", size: 17.0)
        let attrString = NSMutableAttributedString(
            string: substring1 as String,
            attributes: NSDictionary(
                object: font!,
                forKey: NSFontAttributeName) as [NSObject : AnyObject])

        let font1:UIFont? = UIFont(name: "Arial", size: 11.0)
        let attrString1 = NSMutableAttributedString(
            string: substring2 as String,
            attributes: NSDictionary(
                object: font1!,
                forKey: NSFontAttributeName) as [NSObject : AnyObject])

        //appending both attributed strings
        attrString.appendAttributedString(attrString1)

        //assigning the resultant attributed strings to the button
        btnTwoLine?.setAttributedTitle(attrString, forState: UIControlState.Normal)

    }

Salida

ingrese la descripción de la imagen aquí

Shamsudheen TK
fuente
2
Funciona genial. Ahora me pregunto si hay alguna forma de centrar el texto en cada línea y si hay alguna forma de insertar más espacio entre las dos líneas.
Scott
3
puede alinear el texto de ambas líneas al centro. escriba el siguiente código btnTwoLine? .titleLabel? .textAlignment = NSTextAlignment.Center o hágalo usando el archivo del guión gráfico (sección de control-> Alineación)
Shamsudheen TK
¿Puedo saber cuál es el propósito de poner más líneas en el medio?
Shamsudheen TK
Depende del tamaño del botón. Si el botón es grande, entonces las dos líneas de texto estarán justo en el medio, con mucho espacio en la parte superior e inferior. Esa no es la mirada que estaba buscando.
Scott
tienes que aplicar algunos trucos aquí :) puedes poner más líneas en el medio usando múltiples \ n. Quiero decir, "hola \ n \ n \ n allí" te dará tres espacios. sin embargo, no olvide modificar su código var newlineRange: NSRange = buttonText.rangeOfString ("\ n \ n \ n")
Shamsudheen TK
22

Estaba buscando casi el mismo tema, excepto que no necesito dos tamaños de fuente diferentes. En caso de que alguien esté buscando una solución simple:

    let button = UIButton()
    button.titleLabel?.numberOfLines = 0
    button.titleLabel?.lineBreakMode = .byWordWrapping
    button.setTitle("Foo\nBar", for: .normal)
    button.titleLabel?.textAlignment = .center
    button.sizeToFit()
    button.addTarget(self, action: #selector(rightBarButtonTapped), for: .allEvents)
    navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
Nico S.
fuente
12

He notado un problema en la mayoría de las soluciones que es que al hacer el modo de salto de línea en "Ajuste de caracteres", la segunda línea quedará alineada a la izquierda con la primera línea

Centrar todas las líneas. simplemente cambie el título de simple a atribuido y luego puede hacer que cada línea esté centrada

título centrado atribuido

Musa almatri
fuente
6

cambie el salto de línea a ajuste de carácter, seleccione su botón y en el inspector de atributos vaya al salto de línea y cámbielo a ajuste de carácter

ingrese la descripción de la imagen aquí

Sabhay Sardana
fuente
6

Sintaxis de SWIFT 3

let str = NSMutableAttributedString(string: "First line\nSecond Line")
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 17), range: NSMakeRange(0, 10))
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(11, 11))
button.setAttributedTitle(str, for: .normal)
Maksim Kniazev
fuente
2
No estoy seguro de por qué, pero tuve que agregar button.titleLabel? .numberOfLines = 0
budidino
No funcionó en Swift 4 primero. Necesita establecer "salto de línea" en "ajuste de palabra". Gracias hombre :)
Karan Alangat
La respuesta anterior original está a continuación: stackoverflow.com/a/30679547/5318223
Kiril S.
5

He solucionado esto y mi solución estaba solo en el Storyboard.

Cambios:

Se agregó en el Inspector de identidad -> Atributos de tiempo de ejecución definidos por el usuario (estos KeyPaths):

  • numberOfLines = 2
  • titleLabel.textAlignment = 1

Atributos de tiempo de ejecución definidos por el usuario

Agregué esto en el inspector de atributos:

  • salto de línea = ajuste de palabra

Ajuste de línea

A. Trejo
fuente
2

Necesitas hacer algo de esto en código. no puede configurar 2 fuentes diferentes en IB. Además de cambiar el modo de salto de línea a ajuste de caracteres, necesita algo como esto para establecer el título,

override func viewDidLoad() {
        super.viewDidLoad()
        var str = NSMutableAttributedString(string: "First line\nSecond Line")
        str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(17), range: NSMakeRange(0, 10))
        str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(12), range: NSMakeRange(11, 11))
        button.setAttributedTitle(str, forState: .Normal)

    }
rdelmar
fuente
1

Una forma de hacerlo es con etiquetas, supongo. Hice esto y parece que funciona bien. Podría crear esto como un UIButton y luego exponer las etiquetas, supongo. No sé si esto tiene algún sentido.

    let firstLabel = UILabel()

    firstLabel.backgroundColor = UIColor.lightGrayColor()
    firstLabel.text = "Hi"
    firstLabel.textColor = UIColor.blueColor()
    firstLabel.textAlignment = NSTextAlignment.Center
    firstLabel.frame = CGRectMake(0, testButton.frame.height * 0.25, testButton.frame.width, testButton.frame.height * 0.2)
    testButton.addSubview(firstLabel)

    let secondLabel = UILabel()

    secondLabel.backgroundColor = UIColor.lightGrayColor()
    secondLabel.textColor = UIColor.blueColor()
    secondLabel.font = UIFont(name: "Arial", size: 12)
    secondLabel.text = "There"
    secondLabel.textAlignment = NSTextAlignment.Center
    secondLabel.frame = CGRectMake(0, testButton.frame.height * 0.5, testButton.frame.width, testButton.frame.height * 0.2)
    testButton.addSubview(secondLabel)
Scott
fuente
0

mi manera:

func setButtonTitle(title: String, subtitle: String, button: UIButton){
        //applying the line break mode
        button.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
        let title = NSMutableAttributedString(string: title, attributes: Attributes.biggestLabel)
        let subtitle = NSMutableAttributedString(string: subtitle, attributes: Attributes.label)
        let char = NSMutableAttributedString(string: "\n", attributes: Attributes.biggestLabel)
        title.append(char)
        title.append(subtitle)
        button.setAttributedTitle(title, for: .normal)
    }
nastassia
fuente
0

Desafortunadamente, las soluciones sugeridas no funcionaron para mí cuando quería tener un botón de línea múltiple dentro de CollectionView. Luego, un colega me mostró una solución alternativa que quería compartir en caso de que alguien tuviera el mismo problema, ¡espero que esto ayude! Cree una clase que herede de UIControl y extiéndala con una etiqueta, que luego se comportará de manera similar como un botón.

class MultilineButton: UIControl {

    let label: UILabel = {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.numberOfLines = 0
        $0.textAlignment = .center
        return $0
    }(UILabel())

    override init(frame: CGRect) {
        super.init(frame: frame)

        addSubview(label)

        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
            label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
            label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
        ])
    }

    override var isHighlighted: Bool {
        didSet {
            backgroundColor = backgroundColor?.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
            label.textColor = label.textColor.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
        }
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Mitemmetim
fuente