webentwicklung-frage-antwort-db.com.de

ios10: viewDidLoad-Rahmenbreite/-höhe wurde nicht korrekt initialisiert

Seit dem Upgrade auf XCode8 GM und ios10 werden alle meine mit Interface Builder erstellten Ansichten erst viel später als erwartet korrekt initialisiert. Dies bedeutet in viewDidLoad, cellForRowAtIndexPath, viewWillAppear usw. die Frame-Größe für jede Ansicht auf {1000,1000}. Irgendwann scheinen sie zu korrigieren, aber es ist viel zu spät. 

Das erste Problem, das aufgetreten ist, ist die allgemeine Rundung der Ecken, die auf der ganzen Linie versagt:

view.layer.cornerRadius = view.frame.size.width/2

Weitere Probleme zeigen sich für alles, was sich auf die Frame-Größe bezieht, um Berechnungen im Code durchzuführen. 

cellForRowAtIndexPath 

Bei cellForRowAtIndexPath schlägt die Frame-Größe bei der anfänglichen Tabellenanzeige fehl, funktioniert jedoch gut, wenn Sie einen Bildlauf durchführen. willDisplayCell: forRowAtIndexPath hat auch nicht die richtige Framegröße. 

Ich habe ein paar Werte hartcodiert, aber offensichtlich ist dies eine sehr schlechte Codepraxis und in meinen Projekten ziemlich zahlreich.

Gibt es eine Möglichkeit oder einen Ort, um korrekte Rahmengrößen zu erhalten?

EDIT

Ich habe festgestellt, dass die Verwendung der Höhen-/Breitenbeschränkung anstelle der Rahmenbreitenhöhe zuverlässiger ist. Dies kann den zusätzlichen Aufwand verursachen, wenn viele neue IBOutlets erforderlich sind, um die Höhen-/Breitenbeschränkungen für Elemente zu verknüpfen.

Für den Moment habe ich eine UIView-Kategorie erstellt, mit der ich direkt ohne IBOutlets auf die Höhen-/Breitenbeschränkungen einer Ansicht zugreifen kann. Für einen minimalen Einsatz sollte die kleine Schleife keine große Sache sein. Ergebnisse werden nicht für IB-Artikel ohne die festgelegten Breiten-/Höheneinschränkungen garantiert. Gibt wahrscheinlich am besten 0 für die Konstante oder schlechter zurück. Auch wenn Sie keine Einschränkung für die Höhe/Breite haben und Ihre Ansicht basierend auf den führenden/nachlaufenden Einschränkungen dynamisch skaliert wird, funktioniert dies nicht.

-viewDidLoad scheint die richtige Framegröße zu haben, führt jedoch häufig zu einer visuellen Änderung der Benutzeroberfläche, wenn Sie hier Änderungen vornehmen.

UIView + WidthHeightConstraints.h

@interface UIView (WidthHeightConstraints)

-(NSLayoutConstraint*)widthConstraint;
-(NSLayoutConstraint*)heightConstraint;
-(NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute;

@end

UIView + WidthHeightConstraints.m

#import "UIView+WidthHeightConstraints.h"

@implementation UIView (WidthHeightConstraints)

-(NSLayoutConstraint*)widthConstraint{
    return [self constraintForAttribute:NSLayoutAttributeWidth];
}
-(NSLayoutConstraint*)heightConstraint {
    return [self constraintForAttribute:NSLayoutAttributeHeight];
}
-(NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute {
    NSLayoutConstraint *targetConstraint = nil;
    for (NSLayoutConstraint *constraint in self.constraints) {
        if (constraint.firstAttribute == attribute) {
            targetConstraint = constraint;
            break;
        }
    }
    return targetConstraint;
}

@end

EDIT 2

Die oben genannte Kategorie hat sich nur bedingt bewährt. Hauptsächlich, weil ios anscheinend automatisch ein paar zusätzliche Duplikate für zusätzliche Höhen-/Breiteneinschränkungen hinzufügt, die vom Typ NSContentSizeLayoutConstraint sind und eigentlich nicht die gleiche Größe wie die normale Einschränkung haben. Die NSContentSizeLayoutConstraint ist auch eine private Klasse, daher kann ich nicht isKindOfClass verwenden, um diese herauszufiltern. Ich habe noch keinen anderen Weg gefunden, um effektiv darauf zu testen. Das ist nervig.

40
Miro

Die häufigsten Probleme, die Sie beschreiben, treten nur in iOS 10 auf und können durch Hinzufügen dieser Zeile (falls erforderlich) behoben werden:

self.view.layoutIfNeeded()

direkt über dem Code, der für das Ändern der Einschränkung verantwortlich ist, layer.cornerRadius usw.

ODER 

platzieren Sie Ihren Code, der sich auf Frames/Layer bezieht, in der viewDidLayoutSubviews()-Methode:

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()
    view.layer.cornerRadius = self.myView.frame.size.width/2
    view.clipsToBounds = true

    ... etc
}
29
pedrouan

Für das ähnliche Problem haben wir ein Radar (28342777 (als Duplikat für 28221021 (aber offen) markiert) erstellt. Die Antwort lautet wie folgt:

"Vielen Dank, dass Sie uns über das Problem informiert haben. Könnten wir mehr Informationen zur Profilbildansicht erhalten? In Xcode 8 speichert eine nicht verstellte Ansicht mit vollständiger Einschränkung keinen Frame mehr, um Unterschiede zu minimieren und unterstützt die automatische Aktualisierung von Frames in IB. Zur Laufzeit Diese Ansichten werden mit einer Platzhaltergröße von 1000x1000 dekodiert, werden jedoch nach dem ersten Layout aufgelöst. Könnte das Bild vor dem anfänglichen Layout zugewiesen werden und würde das Bild nach der ersten Layout-Adressierung in diesem Fall zugewiesen werden? analysieren wir weiter. danke! "

Derzeit haben wir ihnen das Beispielprojekt zur Verfügung gestellt. Meine Beobachtungen:

  • Das Problem, das wir früher für XIBs hatten, die von Xcode 7.x in Xcode 8.x konvertiert wurden
  • Wenn wir die Einschränkung in XIB absichtlich aufheben, erhält viewDidLoad die erwartete Höhe und Breite und nicht 1000x1000.
  • Für uns war es eine UIImageView, auf der wir einige Layer für das Zirkulieren und MaskenToBounds verwendeten. Wenn wir masksToBounds = NO setzen, funktionierte alles gut. 

Obwohl Apple behauptet, es sei ein Standard von Xcode 8, dass die Ansichten auf 1000x1000 gesetzt werden, scheint das Verhalten nicht konsistent zu sein. 

Hoffe das hilft. 

16
Bhavik Bhagat

Ich bin auf das gleiche Problem gestoßen und habe versucht, es mit den obigen Vorschlägen ohne Erfolg zu lösen.

Anscheinend sollte es ein Fehler sein, den Apple lösen konnte. Endlich finde ich eine Lösung, indem ich mein XIB-Dokument im Xcode 7.x-Format und meine Benutzeroberfläche wieder im Normalzustand speichere.

Bis Apple ein Update veröffentlicht, möchte ich meine Zeit nicht damit verbringen, es zu hacken.

 enter image description here  enter image description here

6
allen

Was ist dabei zu tun: 

- (NSLayoutConstraint*)widthConstraint{
    return [self constraintForAttribute:NSLayoutAttributeWidth];
}

- (NSLayoutConstraint*)heightConstraint {
    return [self constraintForAttribute:NSLayoutAttributeHeight];
}

- (NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute {
    NSLayoutConstraint *targetConstraint = nil;
    for (NSLayoutConstraint *constraint in self.constraints) {
        //NSLog(@"constraint: %@", constraint);
        if (![constraint isKindOfClass:NSClassFromString(@"NSContentSizeLayoutConstraint")]) {
            if (constraint.firstAttribute == attribute) {
                targetConstraint = constraint;
                break;
            }
        }
    }
    return targetConstraint;
}
2
942v

Ich hatte genau das gleiche Problem. Ich hatte eigene UITableViewCell-Unterklassen und verwendete clipsToBounds = YES und self.iconView.layer.cornerRadius = self.iconView.frame.size.width/2, um mir ein kreisförmiges Bild zu geben. Ich habe versucht, meine Zellkonfigurationsmethode von cellForRowAtIndexPath und willDisplayCell aufzurufen, und funktionierte nicht.

Folgendes funktioniert:
Verschieben Sie Ihren Layering-Code wie folgt in die -layoutSubviews-Methode der Zelle:

-(void)layoutSubviews {
    [super layoutSubviews];
    self.iconView.clipsToBounds = YES;
    self.iconView.layer.cornerRadius = self.iconView.frame.size.width/2;
} 

Danach sollten die Bilder ordnungsgemäß geladen werden und der Layer-Code sollte ebenfalls funktionieren.

2
TylerJames

Sie sollten sich nie auf den Zeitpunkt verlassen, wann eine Ansicht angeordnet ist. Wenn das früher für Sie funktioniert hat, dann aus purem Glück. Dafür gibt es in UIKit sehr wenig Garantien. Wenn Sie sich darauf verlassen, dass sich etwas an die Größe Ihrer Ansicht anpasst, müssen Sie layoutSubviews in dieser Ansicht überschreiben und Ihre Einstellungen dort anpassen.

Selbst nachdem Ihre Ansicht vollständig auf dem Bildschirm gerendert wurde, gibt es immer noch so viele Bedingungen, dass sich die Größe der Ansicht ändern kann. Zum Beispiel: Statusleiste mit doppelter Höhe, Multitasking auf dem iPad, Gerätedrehung, um nur einige zu nennen. Daher ist es niemals ratsam, Frame-spezifische Layoutänderungen zu einem bestimmten Zeitpunkt vorzunehmen.

2
Michael Ochs

Nur Update-Frame in Ihrer automatischen Layout-Box .  enter image description here

0
neha mishra