web-dev-qa-db-fra.com

Aligner verticalement le texte dans un UILabel (Remarque: Utilisation de la mise en forme automatique)

Je copie la même question que celle posée avant Question ..__J'ai essayé les solutions données mais je n’ai pas pu la résoudre car sizetofit n’était pas efficace lorsque j’utilise Autolayout.

first screenshot

L'affichage attendu est comme ci-dessous.

second screenshot

61
MELWIN

Modifier

Dans ma réponse initiale, j'utilisais le style de paragraphe de l'étiquette. Il s'avère que pour les étiquettes multilignes, cela empêche en fait que l'étiquette soit multiligne. En conséquence, je l'ai supprimé du calcul. Plus d'informations à ce sujet dans Github

Pour ceux d'entre vous plus habitués à utiliser l'Open Source, regardez certainement TTTAttributedLabel où vous pouvez définir l'alignement du texte de l'étiquette sur TTTAttributedLabelVerticalAlignmentTop


L'astuce consiste à sous-classer UILabel et à remplacer drawTextInRect. Ensuite, assurez-vous que le texte est dessiné à l'origine des limites de l'étiquette.

Voici une implémentation naïve que vous pouvez utiliser maintenant:

Rapide

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawTextInRect(rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            var labelStringSize = stringTextAsNSString.boundingRectWithSize(CGSizeMake(CGRectGetWidth(self.frame), CGFloat.max),
                options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                attributes: [NSFontAttributeName: font],
                context: nil).size
            super.drawTextInRect(CGRectMake(0, 0, CGRectGetWidth(self.frame), ceil(labelStringSize.height)))
        } else {
            super.drawTextInRect(rect)
        }
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.blackColor().CGColor
    }
}

Swift 3

  @IBDesignable class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude),
                                                                            options: NSStringDrawingOptions.usesLineFragmentOrigin,
                                                                            attributes: [NSFontAttributeName: font],
                                                                            context: nil).size
            super.drawText(in: CGRect(x:0,y: 0,width: self.frame.width, height:ceil(labelStringSize.height)))
        } else {
            super.drawText(in: rect)
        }
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.black.cgColor
    }
}

Objectif c

IB_DESIGNABLE
@interface TopAlignedLabel : UILabel

@end

@implementation TopAlignedLabel

- (void)drawTextInRect:(CGRect)rect {
    if (self.text) {
        CGSize labelStringSize = [self.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.frame), CGFLOAT_MAX)
                                                         options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                                      attributes:@{NSFontAttributeName:self.font}
                                                         context:nil].size;
        [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),ceilf(labelStringSize.height))];
    } else {
        [super drawTextInRect:rect];
    }
}

- (void)prepareForInterfaceBuilder {
        [super prepareForInterfaceBuilder];
        self.layer.borderWidth = 1;
        self.layer.borderColor = [UIColor blackColor].CGColor;
}

@end

Depuis que j'ai utilisé IBDesignable, vous pouvez ajouter cette étiquette à un scénarimage et la regarder passer, voici à quoi elle ressemble

enter image description here

128
Daniel Galasko

Si vous n'êtes pas limité par le fait que UILabel a une taille fixe, au lieu d'aligner le texte dans un UILabel, utilisez simplement la contrainte ≥ sur l'étiquette donnée pour en changer la taille.

 enter image description here

C'est la solution la plus élégante utilisant la mise en page automatique. N'oubliez pas de définir numberOfLines à zéro cependant.

37
Nikola Milicevic

Vous pouvez utiliser UITextView au lieu de UILabel:
Décocher "Défilement activé"
Décochez "Editable"
Décocher "Sélectionnable"
Définir la couleur d'arrière-plan sur ClearColor

32
arturdev

J'ai eu le même problème, et voici comment je l'ai résolu. Je viens de modifier la ligne de base sous Inspecteur d'attributs pour l'étiquette. Réglez-le sur "Aligner les centres".

 Setting baseline to Align Centers

8
Oyvkva

Au lieu de cela, j'ai changé la constante d'espace inférieur en priorité @ 250 et résolu mon problème. Et mon label a une hauteur constante avec <= constante

7
Felipe FMMobile

Vous feriez cela en supprimant la hauteur minimale.

Si vous avez besoin d'une hauteur minimale inférieure à l'étiquette, utilisez une vue de conteneur redimensionnée en fonction du contenu de l'étiquette, mais utilisée au minimum.

4
Wain

Il existe une solution simple pour les cas où la hauteur d'une étiquette n'a pas besoin d'être constante: mettez votre Label dans un Stack View. Assurez-vous d’ajouter des constantes de début et de fin au Stack View. Voici une capture d'écran de la procédure à suivre dans le storyboard:

 enter image description here

1
Alexander Poleschuk

J'ai utilisé la solution de @Daniel Golasko et chaque fois que le texte à l'intérieur de UILabel était plus long que ce que UILabel pouvait contenir, le texte commençait à baisser au lieu de rester aligné en haut.

J'ai changé cette ligne pour m'assurer que le texte est correctement aligné

    [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),MIN(ceilf(labelStringSize.height), self.frame.size.height))];
1
ezchen

Swift 4

Vous devez sous-classer UILabel et remplacer le rendu d'affichage du texte.

class UITopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        guard let string = text else {
            super.drawText(in: rect)
            return
        }

        let size = (string as NSString).boundingRect(
            with: CGSize(width: rect.width, height: .greatestFiniteMagnitude),
            options: [.usesLineFragmentOrigin],
            attributes: [.font: font],
            context: nil).size

        var rect = rect
        rect.size.height = size.height.rounded()
        super.drawText(in: rect)
    }
}
1
dimpiax

J'ai eu un problème similaire où il y avait 3 étiquettes. L'étiquette du milieu pourrait avoir un texte beaucoup plus long que les deux autres, de sorte que sa hauteur pourrait devenir beaucoup plus grande. 

Comme ça:

 enter image description here

Je règle la contrainte d'espace du bas de l'étiquette du milieu sur> = l'étiquette du bas.

 enter image description here

Cela a résolu mon problème.

1
Pætur Magnussen

La mise en page automatique fonctionne uniquement avec les bords/tailles du contrôleur, pas avec le contenu des contrôleurs. Ce n’est donc pas une bonne idée d’utiliser la mise en page automatique pour afficher le texte de votre étiquette en haut de la première ligne . alors.

1
EI Captain v2.0
  @IBInspectable var alignTop: Bool = false

  func setAlignTop() {
    let text = self.text!
    let lines = text.characters.split(separator: "\n").count
    if lines < self.numberOfLines {
      var newLines = ""
      for _ in 0..<(self.numberOfLines - lines) {
        newLines = newLines.appending("\n ")
      }
      self.text! = text.appending(newLines)
    }
  }

  override var text: String? {
    didSet {
      if alignTop {
        self.setAlignTop()
      }
    }
  }
0
hojin

Vous pouvez essayer si le bouton [button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];

Modifier : 

Vous pouvez essayer avec ceci si vous voulez utiliser l'étiquette seulement:

https://stackoverflow.com/a/11278660/1223897

0
Yuvrajsinh

use this my class, vous pouvez modifier le texte alignment par contentMode

cas pris en charge: .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight

Swift4

import Foundation
import UIKit

@IBDesignable
class UIAlignedLabel: UILabel {

    override func drawText(in rect: CGRect) {
        if let text = text as NSString? {
            func defaultRect(for maxSize: CGSize) -> CGRect {
                let size = text
                    .boundingRect(
                        with: maxSize,
                        options: NSStringDrawingOptions.usesLineFragmentOrigin,
                        attributes: [
                            NSAttributedStringKey.font: font
                        ],
                        context: nil
                    ).size
                let rect = CGRect(
                    Origin: .zero,
                    size: CGSize(
                        width: min(frame.width, ceil(size.width)),
                        height: min(frame.height, ceil(size.height))
                    )
                )
                return rect

            }
            switch contentMode {
            case .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight:
                let maxSize = CGSize(width: frame.width, height: frame.height)
                var rect = defaultRect(for: maxSize)
                switch contentMode {
                    case .bottom, .bottomLeft, .bottomRight:
                        rect.Origin.y = frame.height - rect.height
                    default: break
                }
                switch contentMode {
                    case .right, .topRight, .bottomRight:
                        rect.Origin.x = frame.width - rect.width
                    default: break
                }
                super.drawText(in: rect)
            default:
                super.drawText(in: rect)
            }
        } else {
            super.drawText(in: rect)
        }
    }

}
0
EvGeniy Ilyin

Voici une amélioration de la solution Swift 3 de Daniel Galasko (ici, vous pouvez également définir le nombre maximal de lignes sans décalage en haut):

import UIKit

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelString = stringTextAsNSString.boundingRect(with: CGSize(width: frame.width, height: .greatestFiniteMagnitude),
                    options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
            super.drawText(in: CGRect(x: 0, y: 0, width: frame.width, height: ceil(labelString.size.height) > frame.height ? frame.height : ceil(labelString.size.height)))
        } else {
            super.drawText(in: rect)
        }
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        layer.borderWidth = 1
        layer.borderColor = UIColor.black.cgColor
    }
}
0
Onno Eberhard

Pour moi, je n’ai pas défini la contrainte de hauteur, le texte grandit toujours à partir du haut de l’étiquette . Les contraintes pour cette étiquette sont haut, gauche, droite . chiffres, donc pas de soucis pour la hauteur.

0
Xiang LI