Wie kann ich die Priorität von Einschränkungen zur Laufzeit ändern?

86

Ich habe eine Ansicht mit dynamischer Höhe und versuche, diese Priorität für die Ansichtshöhe zur Laufzeit zu ändern.

Hier ist mein Teil des Codes;

if (index == 0) {

    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.priority = 1000;

} else if (index == 1) {

    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.priority = 500;

}

Ich ändere den Index mit einer Schaltflächenaktion. Wenn ich diesen Code ausführe, wird folgende Fehlermeldung angezeigt:

*** Assertion failure in -[NSLayoutConstraint setPriority:], /SourceCache/Foundation/Foundation-1141.1/Layout.subproj/NSLayoutConstraint.m:174

Was ist mein Fehler hier?

Le'Kirdok
quelle

Antworten:

171

Wie in der NSLayoutConstraintKlassenreferenz angegeben :

Die Prioritäten dürfen nicht von nicht erforderlich zu erforderlich oder von erforderlich zu nicht erforderlich geändert werden. Eine Ausnahme wird ausgelöst, wenn eine Priorität von NSLayoutPriorityRequiredin OS X oder UILayoutPriorityRequirediOS auf eine niedrigere Priorität geändert wird oder wenn eine niedrigere Priorität auf eine erforderliche Priorität geändert wird, nachdem die Einschränkungen einer Ansicht hinzugefügt wurden. Das Wechseln von einer optionalen Priorität zu einer anderen optionalen Priorität ist auch nach der Installation der Einschränkung in einer Ansicht zulässig.

Verwenden Sie die Priorität 999 anstelle von 1000. Technisch gesehen ist dies nicht unbedingt erforderlich, hat jedoch eine höhere Priorität als alles andere.

Cyrille
quelle
4
Vielen Dank für Ihre nette Antwort, aber wenn ich 999 anstelle von 1000 verwende, kann ich meine Ansicht nicht verbergen, indem ich der Höhenbeschränkung 0 zuweise.
Le'Kirdok
Das ist ein weiteres Problem. Möglicherweise haben Sie andere widersprüchliche Einschränkungen. Wenn Ihr Code nicht mehr abstürzt, Ihre Ansichtsanimation jedoch immer noch falsch ist, markieren Sie diese Frage als gelöst. dann öffne einen anderen.
Cyrille
Schön, es ist kein Problem, andere Werte zu verwenden (999, 900, 500 usw.) :)
user924
7
Ernsthaft? Funktioniert in der iOS-Entwicklung etwas ganz normal? So viele Dinge mussten manuell erledigt und / oder Tonnen von Problemumgehungscode implementiert werden, die auf Systemfehler oder Nichtunterstützung zurückzuführen waren. Entschuldigung für den nicht konstruktiven Kommentar.
Lauten
6
Es scheint, dass diese Einschränkung in iOS 13 entfernt wurde. Ich habe versucht, eine Einschränkung von auf requiredzu ändern , defaultLowund es hat funktioniert. Der gleiche Code, der zum Absturz unter iOS 12 verwendet wurde.
Steven Vandeweghe
52

Ich möchte eine kleine Ergänzung zu Cyrilles Antwort machen.

Wenn Sie eine Einschränkung im Code erstellen, stellen Sie sicher, dass Sie die Priorität festlegen, bevor Sie sie aktivieren. Zum Beispiel:

surveyViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self
                                               attribute:NSLayoutAttributeHeight
                                               relatedBy:NSLayoutRelationEqual
                                                  toItem:self.superview
                                               attribute:NSLayoutAttributeHeight
                                              multiplier:1
                                                constant:0];
surveyViewHeightConstraint.active = YES;
surveyViewHeightConstraint.priority = 999;

Dies würde zu einer Laufzeitausnahme führen.

Das Mutieren einer Priorität von erforderlich zu nicht für eine installierte Einschränkung (oder umgekehrt) wird nicht unterstützt.

Richtige Reihenfolge ist:

surveyViewHeightConstraint.priority = 999;
surveyViewHeightConstraint.active = YES;

Für Swift Version 4+

constraintName.priority = UILayoutPriority(rawValue: 999)
Vipin
quelle
13

Schnelle Version:

myContraint.priority = UILayoutPriority(999.0)
Alex
quelle
8

Wir haben dies immer so gehandhabt, indem wir nicht die Einschränkungskonstante, sondern nur die Priorität geändert haben. In Ihrer Situation gelten beispielsweise zwei Höhenbeschränkungen.

 heightConstraintOne (who's height is set in the storyboard at 150, and priority set at 750)
 heightConstraintTwo (who's height is set in the storyboard at 0, and priority set at 250)

Wenn Sie die Ansicht ausblenden möchten, haben Sie:

heightConstraintTwo.priority = 999;

Ebenso, wenn Sie die Ansicht zeigen möchten:

heightConstraintTwo.priority = 250;
J Andrew McCormick
quelle
5
Cool, verstanden: Verwenden Sie 999 statt 1000. Danke
Brainstray
3

Ich hoffe, dieses Szenario hilft jemandem: Ich hatte zwei Einschränkungen, dass sie sich gegenüberstanden, ich meine, sie konnten nicht gleichzeitig erfüllt werden, im Interface Builder hatte einer von ihnen 1000 Priorität und der andere weniger als 1000 Priorität. Als ich sie im Code änderte, hatte ich diesen Fehler:

Beenden der App aufgrund der nicht erfassten Ausnahme 'NSInternalInconsistencyException', Grund: 'Das Mutieren einer Priorität von erforderlich zu nicht für eine installierte Einschränkung (oder umgekehrt) wird nicht unterstützt. Sie haben die Priorität 250 bestanden und die vorhandene Priorität war 1000. '

dann habe ich sie einfach in der viewDidLoad-Funktion mit den Werten .defaultHigh und .defaultLow initialisiert und dies hat mein Problem behoben.


quelle
1

Nach NSLayoutConstraints classinnen UIKit Module

Wenn die Prioritätsstufe einer Einschränkung unter UILayoutPriorityRequired liegt, ist sie optional. Einschränkungen mit höherer Priorität werden vor Einschränkungen mit niedrigerer Priorität erfüllt. Constraint-Zufriedenheit ist nicht alles oder nichts. Wenn eine Einschränkung 'a == b' optional ist, bedeutet dies, dass wir versuchen werden, 'abs (ab)' zu minimieren. Diese Eigenschaft darf nur im Rahmen der Ersteinrichtung oder optional geändert werden. Nachdem einer Ansicht eine Einschränkung hinzugefügt wurde, wird eine Ausnahme ausgelöst, wenn die Priorität von / in NSLayoutPriorityRequired geändert wird.

Beispiel: - UIButtonEinschränkungen mit verschiedenen Prioritäten -

 func setConstraints() {
        buttonMessage.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -10).isActive = true

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 10)

        leading.isActive = true


        let widthConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)

        let heightConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)


        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)

        trailingToSuperView.priority = 999
        trailingToSuperView.isActive = true

        //leading.isActive = false//uncomment & check it will align to right of the View

        buttonMessage.addConstraints([widthConstraint,heightConstraint])

         }  
Jack
quelle
1
Nein, Sie sollten niemals Einschränkungen in erstellen viewDidLayoutSubviews. Diese Methode kann mehrmals aufgerufen werden, wodurch Ihre App abstürzen kann, wenn Sie dort doppelte Einschränkungen erstellen.
Meilen pro Stunde
0

Ich stand vor dem gleichen Problem. Da einige der oben in iOS 13 genannten Antworten funktionieren, funktioniert das Ändern der Priorität einwandfrei. In iOS 12 führt dies jedoch zum Absturz.

Ich konnte dieses Problem beheben, indem ich das IBOutlet NSLayoutConstraint für diese bestimmte Einschränkung in Storyboard erstellt habe, wobei die Priorität auf 1000 beibehalten wurde. Nachfolgend finden Sie den Code für die Korrektur.

if (Condition) {
    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.isActive = false;
} else if (index == 1) {
    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.isActive = True;
}

Hoffe das hilft!!! Prost

Venkat057
quelle
-3

Jetzt können Sie einfach die IBOutlet-Verbindung für Ihre Einschränkungen verwenden und dann diesen Code verwenden.

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)
Kishore Kumar
quelle