J'ai créé un exemple de projet pour reproduire cela.
J'ai un fichier xib avec un UILabel ayant une contrainte top fixe, début et fin. J'ai ajouté une contrainte minHeight et défini le nombre de lignes à 0.
Je règle le preferredMaxLayoutWidth sur Automatic (coché dans le fichier xib).
Dans viewDidLoad, j'ai ceci:
self.myLabel.layer.borderColor = [[UIColor redColor] CGColor]; self.myLabel.layer.borderWidth = 2.0f;
self.myLabel.text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
Et quand je lance le simulateur sur iPhone 6 ou 6+, je reçois ceci:
Je ne sais pas du tout d'où proviennent ces marges et elles sont proportionnelles au nombre de caractères figurant dans UILabel.
Y a-t-il un paramètre magique que j'ai oublié? Il fonctionne bien sur les appareils iPhone 4 ".
Maintenant, si je ne définit pas preferredMaxLayoutWidth, il ne dispose pas du remplissage supplémentaire, mais cela coupe mes multi-lignes dans UILabel. Cela coupe le texte. Je n'ai pas utilisé Size-Class.
Modifier:
J'ai donc modifié peu de choses sur mon exemple de projet pour correspondre à la situation de mon vrai projet. J'ai ajouté une tableView (avec les contraintes top, lead, bottom et trailing définies sur sa vue parent). Chaque cellule du tableau a 4 étiquettes. L'étiquette du haut a une contrainte de haut, de début et de fin sur le contentView de la cellule et les étiquettes suivantes ont une contrainte verticale sur l'étiquette du dessus. Chaque étiquette a un ensemble de contraintes heightGreaterThan et un ensemble widthGreaterThan.
Voici à quoi cela ressemble sans l’ensemble preferredMaxLayoutWidth (Remarquez comment les étiquettes sont limitées à 1 ligne).
Avec preferredMaxLayoutWidth. Maintenant, UILabel affiche le contenu entier mais a un remplissage en haut et en bas.
Edit2: Exemple de projet: https://www.dropbox.com/s/sdahx9njnsxiv98/MultiLineUILabel.zip?dl=1
Donc ce que j’ai fini par faire était de créer une sous-classe pour l’étiquette et de remplacer setBounds: et de définir le preferredMaxLayoutWidth à ses limites.
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
if (self.preferredMaxLayoutWidth != bounds.size.width) {
self.preferredMaxLayoutWidth = bounds.size.width;
[self setNeedsUpdateConstraints];
}}
De plus, dans la sous-classe UITableViewCell, je remplace les layoutSubiews
- (void)layoutSubviews {
[super layoutSubviews];
[self.contentView layoutIfNeeded];
// labelsCollection is an IBOutletCollection of my UILabel sublasses
for (UILabel *label in self.labelsCollection) {
label.preferredMaxLayoutWidth = label.bounds.size.width;
}}
Cela fonctionne tout le temps. Je pense que la raison de ce comportement étrange est que UILabel est initialement défini à 280px (320px - remplissage de chaque côté) dans le fichier xib mais lors de son exécution, il modifie sa largeur pour prendre en charge les écrans plus grands contraintes, il augmente la largeur, ce qui modifie le paramètre 'preferredMaxLayoutWidth' en une valeur supérieure). Pour une raison quelconque, UILabel ne met pas à jour sa valeur preferredMaxLayoutWidth à la valeur la plus grande et crée un espace blanc en haut et en bas.
C'est mon hypothèse.
J'espère que cela t'aides.
en utilisant cette classe corrigé pour moi
import UIKit
class CustomLabel: 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)
}
}
}
Quiconque cherche déjà dans cette question qui utilise déjà maxPreferredLayoutWidth (au fait, vous n'avez pas besoin de sous-classe, définissez simplement ceci dans viewDidLayoutSubviews de votre VC), vérifiez que vous le définissez à la largeur de la vue correcte.
Le mien ne fonctionnait pas parce que j'avais:
label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label1.frame.width
Quand cela aurait dû être:
label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label2.frame.width
Voyez-vous la différence? Je ne l'ai pas fait pendant 3 heures lol
Y a-t-il une contrainte au bas de l'étiquette? Je crois que cela permet de s’étirer à cause de la priorité liée au contenu. Réglez-le sur 1000 (obligatoire). Cela l'empêchera de s'étendre au-delà de sa taille de texte. Vous devrez ensuite ajouter les contraintes appropriées au bas de l'étiquette.
Tout d'abord les gars, désolé pour mon anglais. Je suis novice en anglais, mais je vais essayer de décrire comment j'ai résolu ce problème.
J'ai fait face à ce problème dans certains de mes projets. Donc, ma solution pour résoudre ce problème est la suivante:
Dans une cellule, j'ai la méthode de configuration suivante: - (void) configureWithSomeObject: parentViewSize: et dans tableView: cellForRowAtIndexPath: J'ai créé une cellule comme ceci:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YourCell *cell;
//cell initialization
[cell configureWithSomeObject:nil parentViewSize:tableView.frame.size];
return cell;
}
Dans les méthodes de configuration, il suffit de définir preferredMaxLayoutWidth en fonction de la largeur du parent:
- (void)configureWithSomeObject:(NSObject)someObject parentViewSize:(CGSize)parentViewSize {
// do your stuff
self.someLabel.preferredMaxLayoutWidth = parentViewSize.width;
}
P.S. si vous avez des espaces de début/fin, vous devez les soustraire de la valeur parentViewSize.width.
J'espère que ça sera utile pour tout le monde :)
Comme je devais définir la compatibilité de preferredMaxLayoutWidth pour iOS 7, j'ai finalement appelé boundingRectWithSize
pour calculer la hauteur d'étiquette requise et définir la constante de contrainte de hauteur exposée pour UILabel.
CGRect labelRect = CGRectIntegral([myText boundingRectWithSize:size
options:options attributes:attributes context:context]);
self.myLabelHeightConstraint.constant = labelRect.size.height;
Donc, voici comment j’ai implémenté cela avec Swift, Dans la classe qui étend UILabel, je remplace la variable bounds par un getter et un setter, qui définit la variable super du moteur et le renvoie, ce qui permet d’ajouter du code. à l'obtenir et définir.
Je dois dire que je ne suis pas convaincu qu'il fasse tout ce qu'il faut pour le moment, j'ai encore de grands espaces ouverts.
override var bounds:CGRect {
get {
return super.bounds
}
set {
super.bounds = newValue
if (self.preferredMaxLayoutWidth != super.bounds.size.width) {
self.preferredMaxLayoutWidth = super.bounds.size.width;
self.setNeedsUpdateConstraints()
}
}
}
UILabel centre le texte verticalement. Je suppose que ce que vous constatez, c’est que vos contraintes entraînent l’extension de la vue de l’étiquette sur le périphérique plus grand, et le texte est, comme prévu, centré verticalement sur la vue de taille.
Vous pouvez également utiliser une UITextView non modifiable avec UIViewContentModeTop.
J'avais un problème similaire, et juste sous-classer UILabel
et remplacer setBounds
ne fonctionnait pas pour moi. En passant setBounds
, j'ai remarqué que la hauteur de l'étiquette était 39,999999993. Alors j'ai fait le changement suivant, pour l'arrondir à 40:
- (void)setBounds:(CGRect)bounds
{
bounds.size.height = ceilf(CGRectGetHeight(bounds));
[super setBounds: bounds];
if (self.preferredMaxLayoutWidth != bounds.size.width)
{
self.preferredMaxLayoutWidth = bounds.size.width;
[self setNeedsUpdateConstraints];
}
}
Cela a résolu le problème pour moi, plus de rembourrage supplémentaire au-dessus et au-dessous de ma UILabel
sur les gros périphériques. Je n'avais pas non plus à définir la priorité du contenu.