Cómo controlar el interlineado en UILabel


274

¿Es posible reducir la brecha entre el texto, cuando se colocan en varias líneas en un UILabel? Podemos establecer el marco, el tamaño de fuente y el número de líneas. Quiero reducir la brecha entre las dos líneas en esa etiqueta.



2
¿Puedo sugerirle que acepte una de las respuestas correctas para iOS 6.0 y versiones posteriores? La respuesta actualmente aceptada no está actualizada.
Mark Amery

Para cada línea use un nuevo UILabel, luego incruste todas las etiquetas en a StackView. Finalmente ajustar el spacingde StackView. Recuerde apilarlos verticalmente.
Miel

Consulte el siguiente enlace para la solución en Swift 2. stackoverflow.com/a/39158698/6602495
Sneha

Consulte stackoverflow.com/a/44325650/342794 para ver los ajustes del guión gráfico y otros detalles.
lal

Respuestas:


262

Pensé en agregar algo nuevo a esta respuesta, así que no me siento tan mal ... Aquí hay una respuesta rápida :

import Cocoa

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 40

let attrString = NSMutableAttributedString(string: "Swift Answer")
attrString.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))

var tableViewCell = NSTableCellView()
tableViewCell.textField.attributedStringValue = attrString

"Respuesta corta: no puedes. Para cambiar el espacio entre líneas de texto, tendrás que subclasificar UILabel y rodar tu propio drawTextInRect, o crear múltiples etiquetas".

Ver: Establecer el espaciado de línea UILabel


Esta es una respuesta muy antigua, y otras ya han agregado la nueva y mejor forma de manejar esto. Consulte las respuestas actualizadas que se proporcionan a continuación.


23
Desde iOS 6.0, puede controlarlo a través de NSAttributedString(también disponible en las propiedades de UILable en el generador de interfaz de Xcode).
ǝʞɾuǝʞ

13
Curiosamente, por lo que puedo decir, puede agregar espacio adicional entre las líneas, pero no reducirlo NSParagraphStyleal usar un NSAttributedString. (Es posible que necesite hacer más pruebas de las otras propiedades modificables, pero la lineSpacingpropiedad solo le permite aumentarla).
livingtech

vea mi respuesta para ver una manera de usar NSAttributedString
d.ennis

2
@livingtech Eso es irritante, y creo que tienes razón. ¿Has encontrado alguna solución?
Dom Vinyard

77
Solo para aclarar algo en este hilo. Si desea reducir el espaciado entre líneas, establezca la altura de la línea en 1.0, y luego establezcaLineHeightMultiple en un valor menor <1.0, como: [párrafoStyle setLineHeightMultiple: 0.8] o
párrafoStyle.lineHeightMultiple

401

En Xcode 6 puedes hacer esto en el guión gráfico:

ingrese la descripción de la imagen aquí


1
¡Aprovecha más ventajas del guión gráfico!
Allen

22
@PaperThick tiene el mismo problema en 6.1.1. Se "sacudió Harlem" durante unos minutos. No sabe cómo solucionarlo :) Xcode Shaking
Anton Gaenko

8
¿Hay alguna manera de configurar fuentes personalizadas de esta manera? Parece que no puedo cambiar esa helvetica neue a ninguna otra fuente.
Marcos Curvello

2
Si habilita 'Atribuido' y luego abre el archivo como código fuente, puede editar el 'lineHeightMultiple' manualmente y, por lo tanto, omitir el error Harlem Shake
ED-209

2
@azdev para cualquiera que todavía esté mirando esto, estoy tomando más tiempo los batidos en Xcode 7.3, pero creo que esta es la primera versión en la que no ha sido un problema
LulzCow

103

A partir de iOS 6, puede establecer una cadena atribuida a UILabel. Verifique lo siguiente:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:label.text];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = spacing;
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, label.text.length)];

label.attributedText = attributedString;

1
El attributedStringdebe ser un NSMutableAttributedString(NO NSAttributedString)
Mike S

14
El primer código de línea debe serNSMutableAttributedString *attributedString = [NSMutableAttributedString alloc]initWithString:@"sample text"];
Allen

La lineSpacingpropiedad del NSMutableParagraphStylenunca es negativa, por lo que la altura de la línea no se puede reducir con este enfoque. Para responder la pregunta, debe usar otra propiedad, vea @ d.ennis answer.
Theo

81

Las soluciones indicadas aquí no funcionaron para mí. Encontré una forma ligeramente diferente de hacerlo con iOS 6 NSAttributeString:

myLabel.numberOfLines = 0; 
NSString* string = @"String with line one. \n Line two. \n Line three.";
NSMutableParagraphStyle *style  = [[NSMutableParagraphStyle alloc] init];
style.minimumLineHeight = 30.f;
style.maximumLineHeight = 30.f;
NSDictionary *attributtes = @{NSParagraphStyleAttributeName : style,};
myLabel.attributedText = [[NSAttributedString alloc] initWithString:string
                                                         attributes:attributtes];   
[myLabel sizeToFit];

1
La altura de la línea depende del tamaño de la fuente. El interlineado es solo eso, el interlineado. Puede hacer que las cosas funcionen simplemente configurando la altura de línea mínima / máxima, pero eso es solo porque los tamaños de fuente actuales que está utilizando no son mayores que los límites de altura de línea. Según la documentación: "... los glifos y gráficos que exceden esta altura se superpondrán a las líneas vecinas ... Aunque este límite se aplica a la línea misma, el espaciado de línea agrega espacio adicional entre líneas adyacentes".
Ari Braginsky

+1, si desea reducir el espacio entre líneas, esto es lo que quiere hacer. El espacio real entre líneas es muy probable que sea 0 de forma predeterminada, es por eso que las personas informan que solo puede aumentarlo. El problema de que el espaciado sea demasiado grande proviene de que la altura de la línea es demasiado grande, es por eso que esto hará el trabajo el 99% del tiempo.
lawicko

1
Esta es la única respuesta que pude encontrar que usa el valor real de altura de línea (en lugar de una relación) común para diseñar aplicaciones como Photoshop, Sketch, CSS, etc.
Albert Bori

35

He hecho esta extensión simple que me funciona muy bien:

extension UILabel {
    func setLineHeight(lineHeight: CGFloat) {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 1.0
        paragraphStyle.lineHeightMultiple = lineHeight
        paragraphStyle.alignment = self.textAlignment

        let attrString = NSMutableAttributedString()
        if (self.attributedText != nil) {
            attrString.append( self.attributedText!)
        } else {
            attrString.append( NSMutableAttributedString(string: self.text!))
            attrString.addAttribute(NSAttributedStringKey.font, value: self.font, range: NSMakeRange(0, attrString.length))
        }
        attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
        self.attributedText = attrString
    }
}

Copie esto en un archivo, para que pueda usarlo así

myLabel.setLineHeight(0.7)

recuerde que si hace esto mientras también usa Storyboard para esta etiqueta, asegúrese de establecer las líneas de su etiqueta en 0
Miel

¿Por qué no configura directamente lineSpacingy olvida la configuración lineHeightMultiple?
Miel

Debido a que la clave para reducir la altura de la línea es 'lineHeightMultiple', no lineSpacing
Agustin Meriles

digamos que quiere que la altura de su línea sea 1.4, ¿por qué no puede simplemente escribir .lineSpacing = 1.4y olvidarse de todo .lineHeightMultiple...
Miel

Ja! Lo intenté y no funcioné, pero me pregunto por qué no veo otras respuestas aquí que no usen su mecanismo, es decir, simplemente establecen directamente el lineSpacing. Ver la respuesta aceptada ...
Honey

33

Desde Interface Builder (Storyboard / XIB):

ingrese la descripción de la imagen aquí

Programáticamente:

SWift 4

Usar extensión de etiqueta

extension UILabel {

    // Pass value for any one of both parameters and see result
    func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {

        guard let labelText = self.text else { return }

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineSpacing
        paragraphStyle.lineHeightMultiple = lineHeightMultiple

        let attributedString:NSMutableAttributedString
        if let labelattributedText = self.attributedText {
            attributedString = NSMutableAttributedString(attributedString: labelattributedText)
        } else {
            attributedString = NSMutableAttributedString(string: labelText)
        }

        // Line spacing attribute
        attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))

        self.attributedText = attributedString
    }
}

Ahora llame a la función de extensión

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"

// Pass value for any one argument - lineSpacing or lineHeightMultiple
label.setLineSpacing(lineSpacing: 2.0) .  // try values 1.0 to 5.0

// or try lineHeightMultiple
//label.setLineSpacing(lineHeightMultiple = 2.0) // try values 0.5 to 2.0

O usando la instancia de etiqueta (solo copie y ejecute este código para ver el resultado)

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40

// Line spacing attribute
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))

// Character spacing attribute
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))

label.attributedText = attrString

Swift 3

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
label.attributedText = attrString

2
Agregue la línea "párrafoStyle.alignment = self.textAlignment" para mantener la alineación original. De lo contrario, el texto quedará alineado.
Nithin Michael

Para cualquiera que pierda puntos suspensivos en textos grandes, use: párrafoStyle.lineBreakMode = .byTruncatingTail
christostsang



11

En Swift y como función, inspirado en DarkDust

// Usage: setTextWithLineSpacing(myEpicUILabel,text:"Hello",lineSpacing:20)
func setTextWithLineSpacing(label:UILabel,text:String,lineSpacing:CGFloat)
{
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = lineSpacing

    let attrString = NSMutableAttributedString(string: text)
    attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))

    label.attributedText = attrString
}

7

Según la respuesta de @Mike, reducir el lineHeightMultiplees el punto clave. Ejemplo a continuación, funciona bien para mí:

    NSString* text = label.text;
    CGFloat textWidth = [text sizeWithAttributes:@{NSFontAttributeName: label.font}].width;
    if (textWidth > label.frame.size.width) {
        NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
        paragraph.alignment = NSTextAlignmentCenter;
        paragraph.lineSpacing = 1.0f;
        paragraph.lineHeightMultiple = 0.75;     // Reduce this value !!!
        NSMutableAttributedString* attrText = [[NSMutableAttributedString alloc] initWithString:text];
        [attrText addAttribute:NSParagraphStyleAttributeName value:paragraph range:NSMakeRange(0, text.length)];
        label.attributedText = attrText;
    }

6

Extensión útil de SWIFT 3 para establecer el espacio entre líneas más fácilmente :)

extension UILabel
{
    func setLineHeight(lineHeight: CGFloat)
    {
        let text = self.text
        if let text = text 
        {

            let attributeString = NSMutableAttributedString(string: text)
            let style = NSMutableParagraphStyle()

           style.lineSpacing = lineHeight
           attributeString.addAttribute(NSParagraphStyleAttributeName,
                                        value: style,
                                        range: NSMakeRange(0, text.characters.count))

           self.attributedText = attributeString
        }
    }
}

5

He encontrado una forma en la que puede establecer la altura real de la línea (no es un factor) e incluso se muestra en vivo en Interface Builder . Sólo tiene que seguir las siguientes instrucciones. El código está escrito en Swift 4 .


Paso # 1: crea un archivo llamado DesignableLabel.swifte inserta el siguiente código:

import UIKit

@IBDesignable
class DesignableLabel: UILabel {
    @IBInspectable var lineHeight: CGFloat = 20 {
        didSet {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.minimumLineHeight = lineHeight
            paragraphStyle.maximumLineHeight = lineHeight
            paragraphStyle.alignment = self.textAlignment

            let attrString = NSMutableAttributedString(string: text!)
            attrString.addAttribute(NSAttributedStringKey.font, value: font, range: NSRange(location: 0, length: attrString.length))
            attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attrString.length))
            attributedText = attrString
        }
    }
}

Paso # 2: Coloque un UILabelen un Storyboard / XIB y establezca su clase en DesignableLabel. Espere a que su proyecto se compile (¡la compilación debe tener éxito!).

Especificando la clase a tu UILabel


Paso 3: Ahora debería ver una nueva propiedad en el panel de propiedades llamada "Altura de línea". ¡Simplemente configure el valor que desee y debería ver los resultados de inmediato!

Establecer altura de línea en propiedades


2

Aquí hay una subclase de UILabel que establece lineHeightMultipley asegura que la altura intrínseca sea lo suficientemente grande como para no cortar el texto.

@IBDesignable
class Label: UILabel {
    override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize
        let padding = (1.0 - lineHeightMultiple) * font.pointSize
        size.height += padding
        return size
    }

    override var text: String? {
        didSet {
            updateAttributedText()
        }
    }

    @IBInspectable var lineHeightMultiple: CGFloat = 1.0 {
        didSet {
            updateAttributedText()
        }
    }

    private func updateAttributedText() {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineHeightMultiple = lineHeightMultiple
        attributedText = NSAttributedString(string: text ?? "", attributes: [
            .font: font,
            .paragraphStyle: paragraphStyle,
            .foregroundColor: textColor
        ])
        invalidateIntrinsicContentSize()
    }
}

el relleno adicional debe ser (lineHeightMultiple - 1.0) * font.pointSize, ¿verdad?
Pavel Alexeev

El código anterior tal cual parece funcionar para mí. Pero tal vez tengas razón. ¿Intentaste tu cambio? @PavelAlexeev
phatmann

No, me quedo con lineSpacing en lugar de lineHeightMultiple :)
Pavel Alexeev

1

En Swift 2.0 ...

Agregar una extensión:

extension UIView {
    func attributesWithLineHeight(font: String, color: UIColor, fontSize: CGFloat, kern: Double, lineHeightMultiple: CGFloat) -> [String: NSObject] {
        let titleParagraphStyle = NSMutableParagraphStyle()
        titleParagraphStyle.lineHeightMultiple = lineHeightMultiple

        let attribute = [
            NSForegroundColorAttributeName: color,
            NSKernAttributeName: kern,
            NSFontAttributeName : UIFont(name: font, size: fontSize)!,
            NSParagraphStyleAttributeName: titleParagraphStyle
        ]
        return attribute
    }
}

Ahora, solo configure su UILabel como atribuidoTexto:

self.label.attributedText = NSMutableAttributedString(string: "SwiftExample", attributes: attributesWithLineHeight("SourceSans-Regular", color: UIColor.whiteColor(), fontSize: 20, kern: 2.0, lineHeightMultiple: 0.5))    

Obviamente, agregué un montón de parámetros que puede que no necesite. Juega un poco, siéntete libre de reescribir el método. Estaba buscando esto en un montón de respuestas diferentes, así que pensé en publicar toda la extensión en caso de que ayude a alguien ... -rab


1

Swift3: en una extensión UITextView o UILabel, agregue esta función:

Agregué un código para mantener el texto atribuido actual si ya está utilizando cadenas atribuidas con la vista (en lugar de sobrescribirlas).

func setLineHeight(_ lineHeight: CGFloat) {
    guard let text = self.text, let font = self.font else { return }

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = 1.0
    paragraphStyle.lineHeightMultiple = lineHeight
    paragraphStyle.alignment = self.textAlignment

    var attrString:NSMutableAttributedString
    if let attributed = self.attributedText {
        attrString = NSMutableAttributedString(attributedString: attributed)
    } else {
        attrString = NSMutableAttributedString(string: text)
        attrString.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, attrString.length))
    }
    attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
    self.attributedText = attrString
}

1

Otra respuesta ... Si está pasando la cadena mediante programación, debe pasar una cadena atribuida en lugar de una cadena normal y cambiar su estilo. (IOS10)

NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc] initWithString:@"Your \nregular \nstring"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:4];
[attrString addAttribute:NSParagraphStyleAttributeName
                   value:style
                   range:NSMakeRange(0, attrString.length)];
_label.attributedText = attrString;

1

Extensión Swift 3:

    import UIKit

extension UILabel {
    func setTextWithLineSpacing(text: String, lineHeightMultiply: CGFloat = 1.3) {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineHeightMultiple = lineHeightMultiply
        paragraphStyle.alignment = .center
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
        self.attributedText = attributedString
    }
}

1

Esto debería ayudar con eso. Luego puede asignar su etiqueta a esta clase personalizada dentro del guión gráfico y usar sus parámetros directamente dentro de las propiedades:

open class SpacingLabel : UILabel {

    @IBInspectable open var lineHeight:CGFloat = 1 {
        didSet {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = 1.0
            paragraphStyle.lineHeightMultiple = self.lineHeight
            paragraphStyle.alignment = self.textAlignment

            let attrString = NSMutableAttributedString(string: self.text!)
            attrString.addAttribute(NSAttributedStringKey.font, value: self.font, range: NSMakeRange(0, attrString.length))
            attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
            self.attributedText = attrString
        }
    } 
}

Esto debería ayudar con eso. Luego puede asignar su etiqueta a esta clase personalizada dentro del guión gráfico y usar sus parámetros directamente dentro de las propiedades.
Russell Warwick el

por favor no ponga contenido relacionado con su respuesta en los comentarios. su respuesta debería ser útil sin tener que leer los comentarios
Neuron

1

Extensión de etiqueta Swift 4. Crear NSMutableAttributedString antes de pasar a la función en caso de que se requieran atributos adicionales para el texto atribuido.

extension UILabel {

    func setLineHeightMultiple(to height: CGFloat, withAttributedText attributedText: NSMutableAttributedString) {

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 1.0
        paragraphStyle.lineHeightMultiple = height
        paragraphStyle.alignment = textAlignment

        attributedText.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedText.length - 1))

        self.attributedText = attributedText
    }
}

0

Este código funcionó para mí (ios 7 y ios 8 seguro).

_label.numberOfLines=2;
_label.textColor=[UIColor whiteColor];

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineHeightMultiple=0.5;
paragraphStyle.alignment = NSTextAlignmentCenter;
paragraphStyle.lineSpacing = 1.0;

NSDictionary *nameAttributes=@{
                               NSParagraphStyleAttributeName : paragraphStyle,
                               NSBaselineOffsetAttributeName:@2.0
                               };


NSAttributedString *string=[[NSAttributedString alloc] initWithString:@"22m\nago" attributes:nameAttributes];
_label.attributedText=string;

0

Aquí está mi solución en rápido. La subclase debería funcionar tanto para la propiedad atribuida de texto y texto como para characterSpacing + lineSpacing. Conserva el espacio si se establece una nueva cadena o atribuidoString.

open class UHBCustomLabel : UILabel {
    @IBInspectable open var characterSpacing:CGFloat = 1 {
        didSet {
            updateWithSpacing()
        }

    }
    @IBInspectable open var lines_spacing:CGFloat = -1 {
        didSet {
            updateWithSpacing()
        }

    }
    open override var text: String? {
        set {
            super.text = newValue
            updateWithSpacing()
        }
        get {
            return super.text
        }
    }
    open override var attributedText: NSAttributedString? {
        set {
            super.attributedText = newValue
            updateWithSpacing() 
        }
        get {
            return super.attributedText
        }
    }
    func updateWithSpacing() {
        let attributedString = self.attributedText == nil ? NSMutableAttributedString(string: self.text ?? "") : NSMutableAttributedString(attributedString: attributedText!)
        attributedString.addAttribute(NSKernAttributeName, value: self.characterSpacing, range: NSRange(location: 0, length: attributedString.length))
        if lines_spacing >= 0 {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = lines_spacing
            paragraphStyle.alignment = textAlignment
            attributedString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
        }
        super.attributedText = attributedString
    }
}

-5

Como una solución rápida-sucia-inteligente-simple:

Para UILabels que no tienen muchas líneas, puede usar stackViews.

  1. Para cada línea escriba una nueva etiqueta.
  2. Incruste en un StackView. (Seleccione ambas etiquetas -> Editor -> Incrustar en -> StackView
  3. Ajuste el SpacingStackView a la cantidad deseada.

Asegúrese de apilarlos verticalmente . Esta solución también funciona para fuentes personalizadas.

ingrese la descripción de la imagen aquí


FWIW esta es una solución terrible pero viable. Por lo tanto lo estoy guardando.
Miel

También he visto un principio que los desarrolladores de iOS usan vistas de pila para crear gráficos. Las vistas de pila son muy poderosas
Honey
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.