Ajuste a altura do UILabel para o texto

112

Eu tenho alguns rótulos que quero ajustar sua altura ao texto, este é o código que escrevi para isso agora

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

EDITAR:

O problema não estava neste pedaço de código, então minha correção está na própria questão. Ainda pode ser útil para outras pessoas!

TheBurgerShot
fonte
Dê uma olhada nas adições do NSString UIKit, existem métodos para calcular o tamanho que você precisa sem criar um UILabel.
Vladimir Gritsenko
@VladimirGritsenko os métodos 'sizeWithFont' não estão disponíveis no Swift :(
TheBurgerShot
Admito que não sou um especialista em Swift, mas acredito que você pode adicionar seus próprios métodos de ponte. Ainda valeria a pena criar UILabel para calcular o tamanho.
Vladimir Gritsenko
@TheBurgerShot sizeWithFontpode não estar disponível para Swift, Stringmas está disponível em NSStringVocê ainda deve ser capaz de chamá-lo assim.
Anorak de
No final das contas, o erro foi algo diferente e não teve nada a ver com esse método. Embora isso ainda possa ser útil para outros.
TheBurgerShot

Respostas:

189

Acabei de colocar isso em um playground e funciona para mim.

Atualizado para Swift 4.0

import UIKit

 func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

let font = UIFont(name: "Helvetica", size: 20.0)

var height = heightForView("This is just a load of text", font: font, width: 100.0)

Swift 3:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    return label.frame.height
}

insira a descrição da imagem aqui

Anoraque
fonte
isso funciona bem para mim também no playground, o erro não parece ocorrer neste lugar específico, quando eu removo os usos deste método ele vai reclamar de alguns println's ou apenas uma linha com apenas comentários (então diz EXC_BAD_ACCESS code = 2 também)
TheBurgerShot
6
Ele funciona em um playground, mas nenhum tamanho ocorre conforme desejado dentro de um controlador de visualização no XCode 6.1
Unome
1
Estou um pouco hesitante em criar um novo UILabeldimensionamento; se esse método for usado internamente layoutSubviewscom a tendência de ser chamado várias vezes por layout completo, a criação do objeto extra pode apresentar atrasos perceptíveis, especialmente durante a rolagem.
Zorayr
deixe textRect = textString.boundingRectWithSize (CGSizeMake (320, 2000), opções: .UsesLineFragmentOrigin, atributos: textAttributes, contexto: nil)
Siddharth Pancholi
Não consigo chamar esta função no meu controlador de visualização ... Você pode me sugerir qual poderia ser a possível razão?
Rouny
64

Se você estiver usando o AutoLayout , poderá ajustar a UILabelaltura apenas pela configuração da IU.

Para iOS8 ou superior

  • Defina a restrição à esquerda / à direita para o seu UILabel
  • E mude as linhas de UILabel1 para 0

insira a descrição da imagem aqui

Para iOS7

  • Primeiro , você precisa adicionar contém altura paraUILabel
  • Então , modifique a relação de EqualparaGreater than or Equal

insira a descrição da imagem aqui

  • Finalmente , mude as linhas de UILabel1 para 0

insira a descrição da imagem aqui

Sua UILabelaltura aumentará automaticamente dependendo do texto

Phan Van Linh
fonte
2
E se o rótulo estiver dentro de uma célula. Quando e como você aumentaria a altura da célula de acordo?
oyalhi
1
@oyalhi, se seu rótulo estiver dentro de uma célula tableview, consulte minha outra postagem stackoverflow.com/a/36277840/5381331
Phan Van Linh
3
Isso funcionou perfeitamente para mim! Configure as restrições e funcionará corretamente!
Bill Thompson,
2
não está funcionando para mim ... a palavra "Label" em um UILabel torna a altura = 20. Permanece 20 após esta configuração.
gadget00
9

Eu crio esta extensão se você quiser

extension UILabel {
    func setSizeFont (sizeFont: CGFloat) {
        self.font =  UIFont(name: self.font.fontName, size: sizeFont)!
        self.sizeToFit()
    }
}
YannSteph
fonte
8

Tenho uma solução de trabalho forte.

em layoutSubviews:

    _title.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 0)
    _title.sizeToFit()
    _title.frame.size = _title.bounds.size

no setter de texto:

    _title.text = newValue
    setNeedsLayout()

UPD. é claro com essas configurações de UILabel:

    _title.lineBreakMode = .ByWordWrapping
    _title.numberOfLines = 0
dimpiax
fonte
6

Apenas definindo:

label.numberOfLines = 0

O rótulo ajusta automaticamente sua altura com base na quantidade de texto inserido.

Jordan Amman
fonte
27
Isso não faz com que o UILabel ajuste sua altura.
TheBurgerShot
6

com base na resposta de Anorak, também concordo com a preocupação de Zorayr, então adicionei algumas linhas para remover o UILabel e retornar apenas o CGFloat, não sei se ajuda, pois o código original não adiciona o UIabel, mas não gera erro, então estou usando o código abaixo:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{

    var currHeight:CGFloat!

    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    currHeight = label.frame.height
    label.removeFromSuperview()

    return currHeight
}
LeftyT
fonte
5

Em Swift 4.1 e Xcode 9.4.1

Apenas 3 etapas

Passo 1)

//To calculate height for label based on text size and width
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat {
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

Passo 2)

//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0

Etapa 3)

//This is your label
let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height))
proNameLbl.text = "This is your text"
proNameLbl.font = UIFont.systemFont(ofSize: 17)
proNameLbl.numberOfLines = 0
proNameLbl.lineBreakMode = .byWordWrapping
infoView.addSubview(proNameLbl)
iOS
fonte
5

A solução sugerida por Anorak como uma propriedade computada em uma extensão para UILabel:

extension UILabel
{
var optimalHeight : CGFloat
    {
        get
        {
            let label = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
            label.numberOfLines = 0
            label.lineBreakMode = self.lineBreakMode
            label.font = self.font
            label.text = self.text

            label.sizeToFit()

            return label.frame.height
         }
    }
}

Uso:

self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight
Philipp Otto
fonte
Ótima solução! Obrigado :-)
Cristina
Não é possível atribuir à propriedade: 'height' é uma propriedade somente para obtenção.
Amg91
4

Seguindo a resposta de @Anorak, adicionei esta extensão a String e enviei um inset como parâmetro, pois muitas vezes você precisará de um preenchimento em seu texto. De qualquer forma, talvez alguns você ache isso útil.

extension String {

    func heightForWithFont(font: UIFont, width: CGFloat, insets: UIEdgeInsets) -> CGFloat {

        let label:UILabel = UILabel(frame: CGRectMake(0, 0, width + insets.left + insets.right, CGFloat.max))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.ByWordWrapping
        label.font = font
        label.text = self

        label.sizeToFit()
        return label.frame.height + insets.top + insets.bottom
    }
}
Lirik
fonte
label.lineBreakMode = NSLineBreakMode.ByWordWrapping esta linha me ajudou, obrigado.
Coder_A_D
3

Aqui está como calcular a altura do texto em Swift. Você pode então obter a altura do retângulo e definir a altura da restrição do rótulo ou textView, etc.

let font = UIFont(name: "HelveticaNeue", size: 25)!
let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"

let textString = text as NSString

let textAttributes = [NSFontAttributeName: font]

let textRect = textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
Collin
fonte
3

apenas chame este método onde você precisa de altura dinâmica para rótulo

func getHeightforController(view: AnyObject) -> CGFloat {
    let tempView: UILabel = view as! UILabel
    var context: NSStringDrawingContext = NSStringDrawingContext()
    context.minimumScaleFactor = 0.8

    var width: CGFloat = tempView.frame.size.width

    width = ((UIScreen.mainScreen().bounds.width)/320)*width

    let size: CGSize = tempView.text!.boundingRectWithSize(CGSizeMake(width, 2000), options:NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: tempView.font], context: context).size as CGSize

    return size.height
}
Shubham bairagi
fonte
3

Swift 4.0

self.messageLabel = UILabel (frame: CGRect (x: 70, y: 60, largura: UIScreen.main.bounds.width - 80, altura: 30)

messageLabel.text = message

messageLabel.lineBreakMode = .byWordWrapping //in versions below swift 3 (messageLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping)    
messageLabel.numberOfLines = 0 //To write any number of lines within a label scope

messageLabel.textAlignment = .center

messageLabel.textColor = UIColor.white

messageLabel.font = messageLabel.font.withSize(12)

messageLabel.sizeToFit()

Blockquote NSParagraphStyle.LineBreakMode, aplica-se a parágrafos inteiros, não a palavras dentro de parágrafos. Essa propriedade tem efeito durante o desenho normal e nos casos em que o tamanho da fonte deve ser reduzido para caber no texto do rótulo em sua caixa delimitadora. Esta propriedade é definida como byTruncatingTail por padrão.

Este link descreve a maneira do storyboard de fazer o mesmo

7ur7l3
fonte
2
Respostas apenas em código não são consideradas boas práticas. Considere adicionar algumas explicações sobre como sua resposta aborda a questão.
Yannis
2

Swift 4.0

Em vez de calcular a altura do texto / etiqueta, apenas redimensiono a etiqueta após inserir o texto (dinâmico).

Supondo que myLabel seja o UILabel em questão:

let myLabel = UILabel(frame: CGRect(x: 0, y: 0, width: *somewidth*, height: *placeholder, e.g. 20*))
myLabel.numberOfLines = 0
myLabel.lineBreakMode = .byWordWrapping
...

E agora vem a parte divertida:

var myLabelText: String = "" {
   didSet {
      myLabel.text = myLabelText
      myLabel.sizeToFit()
   }
}
Patrick J.
fonte
2

O método de extensão Swift 4.1 para calcular a altura do rótulo:

extension UILabel {

    func heightForLabel(text:String, font:UIFont, width:CGFloat) -> CGFloat {
        let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.byWordWrapping
        label.font = font
        label.text = text

        label.sizeToFit()
        return label.frame.height
    }

}

fonte
1

Modo de storyboard Swift 5, XCode 11. Acho que isso funciona para iOS 9 e superior. Você deseja, por exemplo, o rótulo "Descrição" para obter a altura dinâmica, siga as etapas:

1) Selecione o rótulo de descrição -> Vá para o Inspetor de Atributos (ícone de lápis), defina: Linhas: 0 Quebra de Linha: Quebra de Linha

2) Selecione seu UILabel no storyboard e vá para o Inspetor de tamanho (ícone da régua), 3) Vá até "Prioridade de resistência à compressão de conteúdo para 1 para todos os outros componentes UIView (rótulos, botões, imagem, etc) que estão interagindo com seu rótulo.

Por exemplo, eu tenho UIImageView, Title Label e Description Label verticalmente em minha visualização. Eu defino a Prioridade de resistência à compressão de conteúdo como UIImageView e o rótulo do título como 1 e para o rótulo da descrição como 750. Isso fará com que um rótulo de descrição ocupe a altura necessária.

Doci
fonte
0

Para tornar o rótulo dinâmico rapidamente, não forneça constarint de altura e no storyboard faça rótulo número de linhas 0 também fornece restrição inferior e esta é a melhor maneira que estou tratando rótulo dinâmico de acordo com seu tamanho de conteúdo.

Ranjeet Raushan
fonte
0

Você também pode usar a sizeThatFitsfunção.

Por exemplo:

label.sizeThatFits(superView.frame.size).height

Fitsyu
fonte