web-dev-qa-db-fra.com

Autolayout ajoutant un rembourrage supplémentaire en haut et en bas de UILabel iPhone 6/6 + lorsque l'option preferredMaxLayoutWidth est définie

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:

enter image description here

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). No preferredMaxLayoutWidth

Avec preferredMaxLayoutWidth. Maintenant, UILabel affiche le contenu entier mais a un remplissage en haut et en bas. With preferredMaxLayoutWidth but with top and bottom padding

Edit2: Exemple de projet: https://www.dropbox.com/s/sdahx9njnsxiv98/MultiLineUILabel.zip?dl=1

21
newDeveloper

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.

6
newDeveloper

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)
        }
    }

}
1
user1974368

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

1
Abbey Jackson

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. 

0
Henry T Kirk

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:

  1. 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;
    }
    
  2. 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 :)

0
Oleg Sorochich

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;
0
AlexD

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()
            }
        }
    }
0
Mathijs Segers

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.

0
stromdotcom

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.

0
Koen