wake-up-neo.com

Autolayout fügt zusätzliche Polsterung am oberen und unteren Ende des UILabel iPhone 6/6 + hinzu, wenn die Einstellung bevorzugtMaxLayoutWidth festgelegt ist

Ich habe ein Beispielprojekt erstellt, um dies zu reproduzieren.

Ich habe eine Xib-Datei mit einem UILabel, die eine feste Obergrenze, eine führende und eine nachfolgende Einschränkung hat. Ich habe eine MinHeight-Einschränkung hinzugefügt und die Anzahl der Zeilen auf 0 gesetzt.

Ich habe die Einstellung bevorzugterMaxLayoutWidth auf Automatisch gesetzt (in der XIB-Datei eingecheckt).

In viewDidLoad habe ich folgendes:

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.";

Und wenn ich den Simulator auf iPhone 6 oder 6+ laufe, bekomme ich Folgendes:

enter image description here

Ich weiß nicht, woher die obere und untere Polsterung kommt und sie ist proportional zur Anzahl der Zeichen, die im UILabel angezeigt werden.

Gibt es eine magische Einstellung, die ich vergessen habe? Es läuft gut auf iPhone 4 "Geräten.

Wenn ich jetzt nicht die bevorzugte MaxLayoutWidth-Option einstelle, wird die zusätzliche Polsterung nicht verwendet, aber dies unterbricht meine Mehrfachlinien im UILabel. Es schneidet den Text ab. Ich habe Size-Class nicht benutzt.

Bearbeiten:

Daher habe ich an meinem Beispielprojekt einige Änderungen vorgenommen, um die Situation bei meinem tatsächlichen Projekt zu berücksichtigen. Ich habe eine tableView hinzugefügt (mit oberen, führenden, unteren und nachlaufenden Einschränkungen für die übergeordnete Ansicht). Jede Zelle in der tableView hat 4 Beschriftungen. Die obere Beschriftung hat eine obere, eine führende und eine hintere Einschränkung für die Inhaltsansicht der Zelle, und die nachfolgenden Beschriftungen haben eine vertikale Einschränkung für die darüber liegende Beschriftung. Für jedes Etikett gibt es einen heightGreaterThan-Constraint-Satz und einen widthGreaterThan-Satz.

So sieht es aus, ohne dass die Einstellung von PreferMaxLayoutWidth festgelegt wurde (Beachten Sie, wie Beschriftungen auf eine Zeile begrenzt werden). No preferredMaxLayoutWidth

Mit PreferMaxLayoutWidth. Jetzt zeigt das UILabel den gesamten Inhalt, hat jedoch oben und unten eine Auffüllung. With preferredMaxLayoutWidth but with top and bottom padding

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

21
newDeveloper

Am Ende habe ich also eine Unterklasse für das Label erstellt und setBounds überschrieben: und die PreferredMaxLayoutWidth an ihre Grenzen gesetzt.

- (void)setBounds:(CGRect)bounds {
    [super setBounds:bounds];

    if (self.preferredMaxLayoutWidth != bounds.size.width) {
        self.preferredMaxLayoutWidth = bounds.size.width;
        [self setNeedsUpdateConstraints];
}}

In der UITableViewCell-Unterklasse überschreibe ich auch die 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;
}}

Das funktioniert die ganze Zeit. Ich denke, der Grund für dieses seltsame Verhalten ist, dass das UILabel in der xib-Datei anfangs auf 280px (320px - Auffüllen auf beiden Seiten) eingestellt ist, aber während der Laufzeit seine Breite ändert, um größere Bildschirme zu berücksichtigen (da ich das Vor- und Nachlaufbild setze) Einschränkungen erhöht die Breite, wodurch "PreferredMaxLayoutWidth" in einen größeren Wert geändert wird. Aus irgendeinem Grund aktualisiert UILabel nicht seine PreferredMaxLayoutWidth auf den höheren Wert und verursacht den Leerraum oben und unten.

Das ist meine Hypothese.

Hoffe das hilft.

6
newDeveloper

mit dieser Klasse wurde es für mich behoben

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

Jeder, der sich mit dieser Frage befasst, die bereits maxPreferredLayoutWidth verwendet (übrigens müssen Sie keine Unterklasse festlegen, setzen Sie diese Einstellung einfach in viewDidLayoutSubviews Ihres VCs). Überprüfen Sie, ob Sie die Breite der korrekten Ansicht festlegen.

Meine hat nicht funktioniert, weil ich hatte:

label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label1.frame.width

Wenn es hätte sein sollen:

label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label2.frame.width

Siehst du den unterschied Ich habe 3 Stunden lang nicht gelacht

1
Abbey Jackson

Gibt es eine Einschränkung am unteren Rand des Etiketts? Ich glaube, dass es erlaubt, sich zu strecken, weil der Inhalt Priorität hat. Setzen Sie den Wert auf 1000 (erforderlich). Dadurch wird verhindert, dass es über die Textgröße hinaus expandiert. Sie müssen dann am Rand des Etiketts die richtigen Einschränkungen hinzufügen. 

0
Henry T Kirk

Vor allem Jungs, entschuldige mein Englisch. Ich bin Neuling auf Englisch, aber ich werde versuchen zu beschreiben, wie ich dieses Problem behoben habe.

In einigen meiner Projekte bin ich mit diesem Problem konfrontiert. Meine Lösung zur Behebung dieses Problems lautet also:

  1. In einer Zelle habe ich die folgende Konfigurationsmethode: - (void) configureWithSomeObject: parentViewSize: und in tableView: cellForRowAtIndexPath: Ich habe eine Zelle wie folgt erstellt:

    - (UITableViewCell *)tableView:(UITableView *)tableView  cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    YourCell *cell;
    
    //cell initialization
    
    [cell configureWithSomeObject:nil parentViewSize:tableView.frame.size];
    
    return cell;
    }
    
  2. Innerhalb der Konfigurationsmethoden setzen Sie bevorzugtermaxLayoutWidth entsprechend der Breite des übergeordneten Elements:

     - (void)configureWithSomeObject:(NSObject)someObject parentViewSize:(CGSize)parentViewSize {
    // do your stuff
    
    self.someLabel.preferredMaxLayoutWidth = parentViewSize.width;
     }
    

P.S. Falls Sie führende/nachgestellte Leerzeichen haben, sollten Sie sie vom Wert für parentViewSize.width subtrahieren.

Hoffe, es wird für jeden nützlich sein :)

0
Oleg Sorochich

Da ich für die Kompatibilität mit iOS 7 PreferredMaxLayoutWidth einstellen musste, rief ich schließlich boundingRectWithSize an, um die erforderliche Etikettenhöhe zu berechnen und die Konstante für die exponierte Höhenbegrenzung für das UILabel festzulegen.

CGRect labelRect = CGRectIntegral([myText boundingRectWithSize:size 
    options:options attributes:attributes context:context]);
self.myLabelHeightConstraint.constant = labelRect.size.height;
0
AlexD

So habe ich dies auf Swift implementiert, In der Klasse, die das UILabel erweitert, überschreibe ich die Grenzen var mit einem Getter und Setter, der die Grenzen des Supers setzt und sie zurückgibt. Auf diese Weise können Sie Code hinzufügen zum bekommen und einstellen.

Ich muss sagen, dass ich nicht überzeugt bin, dass es die ganze Magie noch tut, ich habe immer noch große offene Räume.

    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 zentriert den Text vertikal. Ich schätze, was Sie sehen, ist, dass Ihre Einschränkungen dazu führen, dass sich die Ansicht des Labels auf dem größeren Gerät erstreckt und der Text sich wie erwartet vertikal auf der Größenansicht zentriert.

Sie können stattdessen versuchen, eine nicht bearbeitbare UITextView mit UIViewContentModeTop zu verwenden.

0
stromdotcom

Ich hatte ein ähnliches Problem und nur die Unterklasse UILabel und die überschreibende setBounds hat für mich nicht funktioniert. Beim Durchlaufen von setBounds fiel mir auf, dass die Höhe des Etiketts 39,999999993 betrug. Also habe ich folgende Änderung vorgenommen, um es auf 40 zu runden: 

- (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];
    }
}

Dies behebte es für mich, keine zusätzlichen Polsterungen über und unter meiner UILabel auf großen Geräten. Ich musste auch nicht die Priorität der Inhalte sehr wichtig einstellen.

0
Koen