2014-07-07 11 views
18

Beim programmatischen Erstellen von Layouts befolge ich Apples Ratschlag: override -updateConstraints, füge benutzerdefinierte Einschränkungen hinzu und fange setNeedsUpdateConstraints ein, sobald Subviews zur Ansicht hinzugefügt wurden. Mein typischer Aufbau sieht wie folgt aus:Autolayout und programmatische Einschränkungen: Wie behandelt man updateConstraints mehrere Male?

- (void)setupViews 
{ 
    //Style View 

    //Add gesture recognizers 

    //Add Subviews 


    [self setNeedsUpdateConstraints]; 
} 

- (void)updateConstraints 
{ 
    //Add custom constraints  

    [super updateConstraints]; 
} 

Das Problem

Es gibt Gelegenheiten, bei denen -updateConstraints mehrmals gefeuert wird (zum Beispiel, wenn ein Controller Ansicht w/Animation präsentiert oder geschoben). Das Problem hierbei ist, dass jede hinzugefügte Bedingung neu hinzugefügt wird. Dies wird zu einem ernsthaften Problem, wenn versucht wird, auf Anforderung die Konstante einer hinzugefügten Beschränkung zu ändern, da zwei der ursprünglichen Bedingungen in der Folge miteinander in Konflikt stehen. Ich stelle mir vor, dass du, selbst wenn du die Beschränkungen nicht manipulierst, nachdem du sie erstellt hast, doppeltes hast, was dir nicht gut erscheint.

Mögliche Lösungen

1 - alle Einschränkungen Entfernen Sie die Ansicht zu bewirken, bevor sie in -updateConstraints Anwendung:

- (void)updateConstraints 
    { 
     //Remove all constraints affecting view & subviews 

     //Add custom constraints 

     [super updateConstraints];  
    } 

2 - Legen Sie ein Layout-Flag & Prüfung gegen sie vor benutzerdefinierten Einschränkungen hinzu:

- (void)updateConstraints 
{ 
    if (self.didAddConstraints) { 
     [super updateConstraints]; 
     return; 
    } 

    //Add custom constraints 

    self.didAddConstraints = YES;  

    [super updateConstraints]; 
} 

3 - Machen Sie sich keine Sorgen über die Verdoppelung der Beschränkungen, und Wenn eine Konstante geändert werden muss, entfernen Sie diese Einschränkung nur, bevor Sie sie erneut hinzufügen.

3 - Etwas tolles, an das ich nicht gedacht habe.


Was ist die beste Praxis hier?

+0

Ich denke, Sie könnten 'setNeedsUpdateConstraints' und' updateConstraints' missbrauchen. Sie haben das Aktualisieren von Konstanten erwähnt - in diesem Fall brauchen Sie nur 'setNeedsLayout'. Mein Verständnis ist, dass "updateConstraints" für Großhandelsänderungen am Layout gedacht ist - wenn Sie die Struktur der Ansicht ändern, nicht nur Parameter. Es ist vorgesehen, einen Platz/Zeit zu haben, um die Beschränkungen dramatisch zu ändern, um eine Änderung der Aktualisierung nach kleinen Zustandsänderungen zu vermeiden.Das heißt, in der State-Eigenschaft Einstellungscode, aktualisieren Sie auch die spezifische entsprechende Einschränkung, und rufen Sie setNeedsDisplay. –

Antwort

17

Kurze Antwort: Mögliche Lösung Nummer 2.

aus- und alle Einschränkungen erneute Anwendung kann teuer werden, wie das Layout komplexer wird. Außerdem, wenn Ihr Layout statusbehaftet ist, haben Sie mehr Probleme.

Verdoppelung Einschränkungen ist sehr ineffizient, Sie können nie wissen, wie oft updateConstraints genannt werden könnte.

Wie this blog post zeigt, ist die Verwendung eines Flags der einfachste und effizienteste Weg, um mit diesem Problem umzugehen. So gehe ich selbst damit um.

Als Randnotiz erwähnen Sie dort eine tolle Möglichkeit, an die Sie noch nicht gedacht haben. Meistens ist der einfachste Weg der beste Weg. :)

+3

stimme ich zu, und das ist in der Regel, was Apple UIKit Ingenieure empfehlen. Der wichtigste Punkt ist, keine Einschränkungen zu entfernen, nachdem die Auto-Layout-Engine einen Layout-Durchlauf durchgeführt hat - es ist unglaublich teuer, einige Einschränkungen zu entfernen, weitere hinzuzufügen und das Layout neu zu berechnen. Wenn Sie Änderungen an Constraints vornehmen möchten, passen Sie die Eigenschaft "constant" an die vorhandenen an, da dies für das automatische Layout-Engine sehr effizient ist. – smileyborg

+0

Ich möchte auch darauf hinweisen, dass (wie die Dokumentation von Apple zu diesen Methoden sagt) ** Sie am Ende Ihrer Implementierung "super" nennen müssen **. Wenn Sie es aufrufen, bevor Sie einige Einschränkungen ändern, können Sie eine Laufzeitausnahme (Absturz) treffen. Normalerweise ist dies kein Problem, aber es kann für bestimmte Einschränkungen auftreten (z. B. eine Höheneinschränkung für die View-Controller-Ansicht, deren Methode '-updateViewConstraints' aufgerufen wird). – smileyborg

+0

Ich frage mich, was ist falsch mit dem Hinzufügen der Einschränkungen in einer 'init' (includes' watchFromNib') -Methode? Ich fühle mich wirklich unwohl mit einer zusätzlichen Flagge var. – CopperCash

0

Diese Art von Tracking konnte auch für die Ersteinrichtung durchgeführt werden. In den meisten Fällen.

override func updateConstraints() { 
      if constraints.count == 0 { 
       let views = ["textField": textField] 
       addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[textField]-0-|", options: [], metrics: nil, views: views)) 
       addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[textField]-0-|", options: [], metrics: nil, views: views)) 
      } 
      super.updateConstraints() 
     } 
Verwandte Themen