Como controlar o espaçamento entre linhas no UILabel


274

É possível reduzir a diferença entre o texto, quando colocado em várias linhas em um UILabel? Podemos definir o quadro, tamanho da fonte e número de linhas. Eu quero reduzir a diferença entre as duas linhas nesse rótulo.



2
Posso sugerir que você aceite uma das respostas corretas para o iOS 6.0 e posterior? A resposta atualmente aceita está desatualizada.
— Mark Amery

Para cada linha, use um novo UILabele incorpore todos os rótulos a StackView. Finalmente ajuste o spacingde StackView. Lembre-se de empilhá-los verticalmente.
— Querida

Consulte o link a seguir para obter a solução no Swift 2. stackoverflow.com/a/39158698/6602495
— Sneha

Consulte stackoverflow.com/a/44325650/342794 para obter detalhes sobre o storyboard e outros detalhes.
— lal

Respostas:


262

Pensei em adicionar algo novo a esta resposta, para não me sentir tão mal ... Aqui está uma resposta 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

"Resposta curta: você não pode. Para alterar o espaçamento entre linhas de texto, você terá que subclassificar UILabel e rolar seu próprio drawTextInRect, ou criar vários rótulos."

Consulte: Definir espaçamento entre linhas do UILabel


Esta é uma resposta muito antiga e outras já adicionaram a nova e melhor maneira de lidar com isso. Consulte as respostas atualizadas fornecidas abaixo.


23
Desde o iOS 6.0, você pode controlá-lo via NSAttributedString(também disponível nas propriedades do UILable no construtor de interface do Xcode).
— ıɾuǝʞ

13
Curiosamente, o mais próximo que posso dizer, você pode adicionar espaçamento extra entre as linhas, mas não reduzi-lo através do NSParagraphStyleuso de um NSAttributedString. (I pode precisar de fazer mais testes das outras propriedades modifyable, mas a lineSpacingpropriedade só permite aumentá-lo.)
— livingtech

veja a minha resposta para ver uma maneira usando NSAttributedString
— d.ennis

2
@livingtech Isso é irritante, e acredito que você está correto. Você encontrou alguma solução alternativa?
— Dom Vinyard

7
Apenas para esclarecer algo nesta discussão. Se você deseja reduzir o espaçamento entre linhas definir a altura da linha para 1,0, e depois setLineHeightMultiple para um valor inferior <1,0, como: [paragraphStyle setLineHeightMultiple: 0.8] ou paragraphStyle.lineHeightMultiple = 0,8
— virsunen

401

No Xcode 6, você pode fazer isso no storyboard:

insira a descrição da imagem aqui


1
Tire mais vantagens do storyboard!
— Allen

22
O @PaperThick tem o mesmo problema no 6.1.1. "Harlem shake" por alguns minutos. Não sabe como corrigi-lo :) Xcode Shaking
— Anton Gaenko 16/01

8
Existe uma maneira de definir fontes personalizadas dessa maneira? Não consigo mudar essa helvética neue para nenhuma outra fonte.
— Marcos Curvello

2
Se você habilitar 'Attributed' e, em seguida, abrir o arquivo como código-fonte, poderá editar o 'lineHeightMultiple' manualmente e, portanto, ignorar o bug do Harlem Shake
— ED-209

2
@azdev para qualquer um que ainda esteja olhando para isso, eu estou mais começando a sacudir no Xcode 7.3, mas acho que essa é a primeira versão em que não tem sido um problema
— #

103

A partir do iOS 6, você pode definir uma sequência atribuída ao UILabel. Verifique o seguinte:

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
O attributedStringdeve ser um NSMutableAttributedString(NÃO NSAttributedString)
— Mike S

14
O primeiro código de linha deve serNSMutableAttributedString *attributedString = [NSMutableAttributedString alloc]initWithString:@"sample text"];
— Allen

A lineSpacingpropriedade do NSMutableParagraphStylenunca é negativa; portanto, a altura da linha não pode ser reduzida com essa abordagem. Para responder à pergunta, você precisa usar outra propriedade, consulte @ d.ennis answer.
— Theo

81

As soluções indicadas aqui não funcionaram para mim. Encontrei uma maneira ligeiramente diferente de fazer isso com o 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
A altura da linha depende do tamanho da fonte. O espaçamento entre linhas é exatamente isso, espaçamento entre linhas. Você pode resolver o problema definindo apenas a altura da linha mínima / máxima, mas isso ocorre apenas porque os tamanhos de fonte atuais que você está usando não são maiores que os limites da altura da linha. De acordo com a documentação: "... glifos e gráficos que excedem essa altura se sobrepõem às linhas vizinhas ... Embora esse limite se aplique à própria linha, o espaçamento entre linhas adiciona espaço extra entre as linhas adjacentes".
— Ari Braginsky 17/10

+1, se você deseja reduzir o espaçamento entre linhas, é isso que você deseja fazer. O espaçamento real das linhas provavelmente é 0, por padrão, é por isso que as pessoas relatam que você só pode aumentá-lo. O problema de o espaçamento ser muito grande vem da altura da linha ser muito grande, é por isso que isso fará o trabalho 99% do tempo.
— lawicko

1
Esta é a única resposta que pude encontrar que usa o valor real da altura da linha (em vez de uma proporção) comum para projetar aplicativos como Photoshop, Sketch, CSS etc.
— Albert Bori

35

Eu fiz essa extensão simples que funciona muito bem para mim:

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 isso em um arquivo, para que você possa usá-lo assim

myLabel.setLineHeight(0.7)

lembre-se de fazer isso enquanto você também está usando o Storyboard para esse rótulo, defina as linhas do rótulo como 0
— Honey

Por que você simplesmente não define diretamente lineSpacinge esquece a configuração lineHeightMultiple?
— Mel

Porque a chave para reduzir a altura da linha é 'lineHeightMultiple', não linespacing
— Agustin Meriles

diz que quer sua altura linha para ser 1.4, por que você não pode simplesmente escrever .lineSpacing = 1.4e esquecer tudo sobre .lineHeightMultiple...
— Mel

Hah! Tentei e não funcionei, mas me pergunto por que não vejo outras respostas aqui sem usar seu mecanismo, quero dizer que elas apenas definem diretamente o espaçamento entre linhas. Veja a resposta aceita ...
— Mel

33

No Interface Builder (Storyboard / XIB):

insira a descrição da imagem aqui

Programaticamente:

SWift 4

Usando extensão 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
    }
}

Agora chame a função de extensão

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

Ou usando a instância do rótulo (basta copiar e executar este código para ver o 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
Adicione a linha "paragraphStyle.alignment = self.textAlignment" para manter o alinhamento original. Caso contrário, o texto será alinhado à esquerda.
— Nithin Michael 29/04/19

Para quem perde reticências em textos grandes, use: paragraphStyle.lineBreakMode = .byTruncatingTail
— christostsang



11

Em Swift e em função, inspirado no 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

De acordo com a Resposta do @Mike, reduzir o lineHeightMultipleé o ponto principal. Exemplo abaixo, funciona bem para mim:

    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

Extensão útil do SWIFT 3 para definir espaço entre linhas com mais facilidade :)

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

Eu encontrei uma maneira em que você pode definir a altura real da linha (não é um fator) e até renderiza no Interface Builder . Apenas siga as instruções abaixo. O código está escrito no Swift 4 .


Etapa 1: Crie um arquivo nomeado DesignableLabel.swifte insira o seguinte 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
        }
    }
}

Etapa 2: Coloque um UILabelem um Storyboard / XIB e defina sua classe como DesignableLabel. Aguarde a construção do seu projeto (a construção deve ser bem-sucedida!).

Especificando a classe para seu UILabel


Etapa 3: Agora você deve ver uma nova propriedade no painel de propriedades denominada "Altura da linha". Basta definir o valor desejado e você verá os resultados imediatamente!

Definir altura da linha nas propriedades


2

Aqui está uma subclasse de UILabel que define lineHeightMultiplee garante que a altura intrínseca seja grande o suficiente para não cortar o 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()
    }
}

preenchimento extra deve ser (lineHeightMultiple - 1.0) * font.pointSize, certo?
— Pavel Alexeev

O código acima como está parecia funcionar para mim. Mas talvez você esteja certo. Você tentou a sua mudança? @PavelAlexeev
— phatmann

Não, eu fico com lineSpacing em vez de lineHeightMultiple :)
— Pavel Alexeev

1

No Swift 2.0 ...

Adicione uma extensão:

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

Agora, basta definir seu UILabel como attributeText:

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

Obviamente, adicionei vários parâmetros que talvez você não precise. Brinque - sinta-se à vontade para reescrever o método - Eu estava procurando isso em várias respostas diferentes, então achei que postaria toda a extensão, caso isso ajude alguém por aí ... -rab


1

Swift3 - Em uma extensão UITextView ou UILabel, adicione esta função:

Adicionei algum código para manter o texto atribuído atual, se você já estiver usando cadeias atribuídas com a visualização (em vez de substituí-las).

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

Outra resposta ... Se você estiver passando a sequência de forma programática, precisará passar uma sequência atribuída em vez de uma sequência regular e alterar seu 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

Extensão 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

Isso deve ajudar com isso. Em seguida, você pode atribuir seu rótulo a essa classe personalizada no storyboard e usá-lo diretamente nos parâmetros:

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

Isso deve ajudar com isso. Em seguida, você pode atribuir seu rótulo a essa classe personalizada no storyboard e usá-lo diretamente dentro das propriedades.
— Russell Warwick

não coloque conteúdo relacionado à sua resposta nos comentários. sua resposta deve ser útil sem ter que ler através dos comentários
— Neuron

1

Extensão de etiqueta Swift 4. Criando NSMutableAttributedString antes de passar para a função, caso haja atributos adicionais necessários para o texto atribuído.

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 funcionou para mim (iOS 7 e iOS 8, com certeza).

_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

Aqui está a minha solução rapidamente. A subclasse deve funcionar para as propriedades attributeText e text e para characterSpacing + lineSpacing. Ele mantém o espaçamento se uma nova string ou attributeString for configurada.

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 uma solução rápida, rápida, suja, inteligente e simples:

Para UILabels que não têm muitas linhas, você pode usar o stackViews.

  1. Para cada linha, escreva um novo rótulo.
  2. Incorpore-os ao StackView. (Selecione os dois rótulos -> Editor -> Incorporar -> StackView
  3. Ajuste o SpacingStackView para a quantidade desejada

Empilhe-os verticalmente . Essa solução também funciona para fontes personalizadas.

insira a descrição da imagem aqui


FWIW, esta é uma solução terrível, mas viável. Portanto, eu estou mantendo isso.
— Mel

Eu também vi um princípio do iOS Dev usar stackviews para criar gráficos. Stackviews são muito poderosas
— Mel
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.