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.