2014-01-21 5 views
7

Ich schreibe eine benutzerdefinierte Ansicht, die programmgesteuert initialisiert wird. Ich überschreibe updateConstraints, um alle für diese Ansicht erforderlichen Einschränkungen hinzuzufügen. :Verwenden von automatischem Layout in einer benutzerdefinierten Ansicht, in der Einschränkungen auf Frame basieren

- (void)updateConstraints { 
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]]; 

    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; 
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:0]]; 

    // some more constraints, you get the point 

    self.bottomSpacingConstraint = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-(0.2 * CGRectGetHeight(self.bounds))]; 
    [self addConstraint:self.bottomSpacingConstraint]; 

    [super updateConstraints]; 
} 

Das Problem ist, dass das Äquivalent von self.boundsCGRectZero zurückgibt. Ich habe meine Forschung und nach dieser objc.io article, das wird erwartet, wie der Rahmen nicht festgelegt wird, bis layoutSubviews aufgerufen wird. Er erwähnt auch

Um das System zu zwingen, das Layout einer Ansicht Baum sofort zu aktualisieren, können Sie layoutIfNeeded/layoutSubtreeIfNeeded nennen (auf iOS und OS X beziehungsweise). Dies kann hilfreich sein, wenn die nächsten Schritte darauf basieren, dass der Frame der Ansichten aktuell ist.

Allerdings, wenn ich

hinzufügen
[self setNeedsLayout]; 
[self layoutIfNeeded]; 

Recht vor self.bottomSpacingConstraint in updateConstraints Einstellung, erhalte ich noch eine CGRectZero für den Rahmen zurück. Laut dem Artikel objc.io (und dieser SO answer) sollten diese Methoden Layout auslösen und den Rahmen aktualisieren.

Kann jemand etwas Licht schimmern, wie man das alles arbeiten lässt? Ich interessiere mich für die Lösung sowie eine Erklärung dessen, was verursacht, welche Layout-bezogenen Methoden aufgerufen werden (zum Beispiel scheint es, dass die Änderung einer bestehenden Constraint-Konstante in layoutSubviewssetNeedsUpdateConstraints aufgerufen wird, die dann updateConstraints auslöst und Constraints verursacht mehrfach hinzugefügt werden).

Antwort

2

Ich bin mir ziemlich sicher, dass Sie layoutIfNeeded von updateConstraints nicht anrufen können oder sollten. Die Aktualisierung der Einschränkungen erfolgt in einem früheren Teil des Layout-Zyklus, daher glaube ich nicht, dass dies die gewünschte Wirkung haben wird.

In Ihrem Fall wäre die Lösung die constant Eigenschaft Ihrer bildabhängigen Abhängigkeit in layoutSubviews zu überprüfen, und wenn sie aktualisiert werden muss, aktualisieren Sie sie dort oder rufen Sie setNeedsUpdateConstraints (seien Sie vorsichtig, Schleifen zu verursachen).

Sie gesagt haben, die Einschränkung der Aktualisierung löst einen weiteren Anruf zu updateConstraints - das wahr ist, und ich glaube, Sie updateConstraints missbräuchlich - es ist für Einschränkungen basierend auf Änderungen Ihrer Ansicht Inhalt zu aktualisieren. Sie sollten diese Einschränkungen nur hinzufügen, wenn sie nicht bereits vorhanden sind.

+1

Dies ist, was Apple über 'updateConstraints' sagt: * Implementieren Sie diese Methode, wenn Ihre Sicht benutzerdefinierte Einschränkungen zwischen Ihren Untersichten erstellen muss. * Jetzt heißt es nicht explizit, dass sie ** in **' updateConstraints erstellt werden sollen ', aber das ist es, was es bedeutet, glaube ich. Wenn nicht, wo würde ich diese Einschränkungen erstellen? –

+1

Ich sage nicht, erstellen Sie sie nicht dort. Ich sage nur erstellen sie, wenn sie nicht bereits existieren, da diese Methode mehrmals aufgerufen werden kann. – jrturton

+1

Gut genug, aber ich will auch nicht 'updateConstraints' missbrauchen. Wenn diese Methode nicht wirklich dort ist, wo ich die Beschränkungen erstellen sollte, dann bin ich völlig in Ordnung, sie woanders zu erstellen. Ich habe keine Ahnung, was ein besserer Ort wäre. Wenn 'updateConstraints' * * der richtige Ort ist, werde ich die Erstellung in eine if-Anweisung einbinden, die zuerst nach ihrer Nicht-Existenz sucht. –

Verwandte Themen