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.
L'affichage attendu est comme ci-dessous.
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:
@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
}
}
@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
}
}
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
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.
C'est la solution la plus élégante utilisant la mise en page automatique. N'oubliez pas de définir numberOfLines à zéro cependant.
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
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
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.
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))];
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)
}
}
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:
Je règle la contrainte d'espace du bas de l'étiquette du milieu sur> = l'étiquette du bas.
Cela a résolu mon problème.
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.
@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()
}
}
}
Vous pouvez essayer si le bouton [button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
Modifier :
Vous pouvez essayer avec ceci si vous voulez utiliser l'étiquette seulement:
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)
}
}
}
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
}
}
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.