Ajuster la hauteur de UILabel au texte

112

J'ai quelques étiquettes dont je veux ajuster leur hauteur au texte, c'est le code que j'ai écrit pour cela maintenant

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
}

ÉDITER:

Le problème n'était pas dans ce morceau de code, donc mon correctif est dans la question elle-même. Cela pourrait encore être utile pour les autres!

TheBurgerShot
la source
Jetez un œil aux ajouts de NSString UIKit, il existe des méthodes pour calculer la taille dont vous avez besoin sans créer un UILabel.
Vladimir Gritsenko
@VladimirGritsenko les méthodes 'sizeWithFont' ne sont pas disponibles dans Swift :(
TheBurgerShot
J'avoue que je ne suis pas un expert sur Swift, mais je pense que vous pouvez ajouter vos propres méthodes de pontage. Cela vaudrait toujours la peine de créer UILabel pour calculer la taille.
Vladimir Gritsenko
@TheBurgerShot sizeWithFontn'est peut-être pas disponible pour Swift Stringmais il est disponible sur NSStringVous devriez toujours pouvoir l'appeler là-dessus.
Anorak
En fin de compte, l'erreur était quelque chose de différent et n'avait rien à voir avec cette méthode. Bien que cela puisse encore être utile pour d'autres.
TheBurgerShot

Réponses:

189

Je viens de mettre ça dans une cour de récréation et ça marche pour moi.

Mis à jour pour 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
}

entrez la description de l'image ici

Anorak
la source
cela fonctionne très bien pour moi aussi dans la cour de récréation, l'erreur ne semble pas se produire à cet endroit spécifique, lorsque je supprime les utilisations de cette méthode, cela va pleurnicher à propos de certains println ou juste une ligne avec seulement des commentaires (alors il dit EXC_BAD_ACCESS code = 2 aussi)
TheBurgerShot
6
Cela fonctionne dans une aire de jeux, mais aucun dimensionnement ne se produit comme souhaité à l'intérieur d'un contrôleur de vue dans XCode 6.1
Unome
1
J'hésite un peu à créer un nouveau UILabelpar dimensionnement; si cette méthode est utilisée à l'intérieur layoutSubviewsavec la tendance à être invoquée plusieurs fois par mise en page complète, la création d'objet supplémentaire peut introduire des retards notables, en particulier lors du défilement.
Zorayr
let textRect = textString.boundingRectWithSize (CGSizeMake (320, 2000), options: .UsesLineFragmentOrigin, attributs: textAttributes, context: nil)
Siddharth Pancholi
Je ne peux pas appeler cette fonction dans mon contrôleur de vue ... Pouvez-vous me suggérer quelle pourrait être la raison possible?
Rouny
64

Si vous utilisez la mise en page automatique , vous pouvez ajusterUILabel hauteur uniquement en configurant l'interface utilisateur.

Pour iOS8 ou supérieur

  • Définissez la contrainte de début / de fin pour votre UILabel
  • Et changez les lignes de UILabel1 à 0

entrez la description de l'image ici

Pour iOS7

  • Tout d'abord , vous devez ajouter la hauteur contient pourUILabel
  • Ensuite , modifiez la relation de EqualàGreater than or Equal

entrez la description de l'image ici

  • Enfin , changez les lignes de UILabel1 à 0

entrez la description de l'image ici

Vous UILabelaugmenterez automatiquement la hauteur en fonction du texte

Phan Van Linh
la source
2
Et si l'étiquette est à l'intérieur d'une cellule. Quand et comment augmenteriez-vous la hauteur de la cellule en conséquence?
oyalhi
1
@oyalhi, si votre étiquette est à l'intérieur d'une cellule tableview, veuillez consulter mon autre article stackoverflow.com/a/36277840/5381331
Phan Van Linh
3
Cela a parfaitement fonctionné pour moi! Configurez les contraintes, et cela fonctionnera correctement!
Bill Thompson
2
ne fonctionne pas pour moi ... le mot "Label" dans un UILabel fait hauteur = 20. Il en reste 20 après ce réglage.
gadget00
9

Je crée cette extension si vous le souhaitez

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

J'ai une solution de travail solide.

dans la mise en page

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

dans le setter de texte:

    _title.text = newValue
    setNeedsLayout()

UPD. bien sûr avec ces paramètres UILabel:

    _title.lineBreakMode = .ByWordWrapping
    _title.numberOfLines = 0
dimpiax
la source
6

Juste en réglant:

label.numberOfLines = 0

L'étiquette ajuste automatiquement sa hauteur en fonction de la quantité de texte saisie.

Jordanie Amman
la source
27
Cela ne permet pas à l'UILabel d'ajuster sa hauteur.
TheBurgerShot
6

basé sur la réponse d'Anorak, je suis également d'accord avec l'inquiétude de Zorayr, j'ai donc ajouté quelques lignes pour supprimer l'UILabel et renvoyer uniquement le CGFloat, je ne sais pas si cela aide car le code d'origine n'ajoute pas le UIabel, mais il ne lance pas d'erreur, j'utilise donc le code ci-dessous:

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
la source
5

Dans Swift 4.1 et Xcode 9.4.1

Seulement 3 étapes

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

Étape 2)

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

Étape 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
la source
5

La solution proposée par Anorak comme propriété calculée dans une extension pour 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
         }
    }
}

Usage:

self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight
Philipp Otto
la source
Belle solution! Merci :-)
Cristina
Impossible d'affecter à la propriété: 'height' est une propriété en lecture seule.
Amg91
4

Suite à la réponse @Anorak, j'ai ajouté cette extension à String et envoyé un encart en tant que paramètre, car vous aurez souvent besoin d'un remplissage dans votre texte. Quoi qu'il en soit, peut-être que certains trouveront cela utile.

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
la source
label.lineBreakMode = NSLineBreakMode.ByWordWrapping cette ligne m'a aidé à remercier.
Coder_A_D
3

Voici comment calculer la hauteur du texte dans Swift. Vous pouvez ensuite obtenir la hauteur du rect et définir la hauteur de contrainte de l'étiquette ou du 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
la source
3

appelez simplement cette méthode où vous avez besoin d'une hauteur dynamique pour l'étiquette

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
la source
3

Swift 4.0

self.messageLabel = UILabel (cadre: CGRect (x: 70, y: 60, largeur: UIScreen.main.bounds.width - 80, hauteur: 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, s'applique à des paragraphes entiers, pas à des mots dans des paragraphes. Cette propriété est en vigueur à la fois pendant le dessin normal et dans les cas où la taille de la police doit être réduite pour s'adapter au texte de l'étiquette dans son cadre de délimitation. Cette propriété est définie sur byTruncatingTail par défaut.

Ce lien décrit la façon dont le storyboard fait de même

7ur7l3
la source
2
Les réponses basées uniquement sur le code ne sont pas considérées comme une bonne pratique. Veuillez envisager d'ajouter quelques explications sur la manière dont votre réponse répond à la question.
Yannis
2

Swift 4.0

Au lieu de calculer la hauteur du texte / étiquette, je redimensionne simplement l'étiquette après avoir inséré le texte (dynamique).

En supposant que myLabel est le UILabel en question:

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

Et maintenant vient la partie amusante:

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

La méthode d'extension Swift 4.1 pour calculer la hauteur de l'étiquette:

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
    }

}

la source
1

Swift 5, manière de storyboard XCode 11. Je pense que cela fonctionne pour iOS 9 et supérieur. Vous voulez par exemple que le libellé "Description" obtienne la hauteur dynamique, suivez les étapes:

1) Sélectionnez l'étiquette de description -> Accédez à l'inspecteur d'attributs (icône de crayon), définissez: Lignes: 0 Saut de ligne: Retour à la ligne

2) Sélectionnez votre UILabel dans le storyboard et accédez à l'inspecteur de taille (icône de règle), 3) Descendez à «Priorité de résistance à la compression du contenu à 1 pour tous les autres composants UIView (étiquettes, boutons, imageview, etc.) qui interagissent avec votre étiquette.

Par exemple, j'ai dans ma vue UIImageView, Title Label et Description Label verticalement. J'ai défini la priorité de résistance à la compression du contenu sur UIImageView et l'étiquette de titre sur 1 et pour l'étiquette de description sur 750. Cela fera qu'une étiquette de description prenne autant de hauteur que nécessaire.

Doci
la source
0

Pour rendre l'étiquette dynamique dans Swift, ne donnez pas de constarint de hauteur et dans le storyboard, le nombre de lignes de l'étiquette 0 donne également une contrainte de fond et c'est la meilleure façon de gérer l'étiquette dynamique en fonction de la taille de leur contenu.

Ranjeet Raushan
la source
0

Vous pouvez aussi utiliser sizeThatFits fonction.

Par exemple:

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

Fitsyu
la source