2015-07-02 4 views
36

Ho una vista con altezza dinamica e sto provando a modificare questa priorità altezza vista in fase di esecuzione.Come modificare la priorità dei vincoli in fase di esecuzione

Ecco la mia parte di codice;

if (index == 0) { 

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

} else if (index == 1) { 

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

} 

Sto cambiando indice con un'azione di pulsante. Quando eseguo questo codice, visualizzo questo errore:

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

Qual è il mio errore qui?

risposta

93

come indicato in NSLayoutConstraint class reference:

Priorities may not change from nonrequired to required, or from required to nonrequired. An exception will be thrown if a priority of NSLayoutPriorityRequired in OS X or UILayoutPriorityRequired in iOS is changed to a lower priority, or if a lower priority is changed to a required priority after the constraints is added to a view. Changing from one optional priority to another optional priority is allowed even after the constraint is installed on a view.

Usa priorità 999 invece di 1000. Non sarà assolutamente necessario tecnicamente parlando, ma sarà una priorità più alta di qualsiasi altra cosa.

+2

Grazie per la tua bella risposta, ma se uso 999 anziché 1000, non posso nascondere la mia vista assegnando 0 al vincolo di altezza. –

+0

Questo è un altro problema. Potresti avere altri vincoli in conflitto. Se il tuo codice non si arresta più, ma l'animazione della tua vista non è ancora corretta, segna questa domanda come risolta; quindi aprirne un altro. – Cyrille

5

Il modo in cui abbiamo sempre gestito questo è non cambiando la costante del vincolo, solo la priorità. Ad esempio, nella tua situazione hai due limiti di altezza.

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) 

se si desidera nascondere la vista, è:

heightConstraintTwo.priority = 999; 

allo stesso modo, se si vuole mostrare la vista:

heightConstraintTwo.priority = 250; 
+0

Fantastico, capito: usa 999 anziché 1000. Grazie – brainray

18

Voglio fare una piccola aggiunta alla Cyrille di risposta.

Se si crea un vincolo nel codice, assicurarsi di impostarne la priorità prima di renderlo attivo. Ad esempio:

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

Ciò comporterebbe un'eccezione runtime.

Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported.

ordine corretto è:

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

Secondo NSLayoutConstraints class all'interno UIKit Module

If a constraint's priority level is less than UILayoutPriorityRequired, then it is optional. Higher priority constraints are met before lower priority constraints. Constraint satisfaction is not all or nothing. If a constraint 'a == b' is optional, that means we will attempt to minimize 'abs(a-b)'. This property may only be modified as part of initial set up or when optional. After a constraint has been added to a view, an exception will be thrown if the priority is changed from/to NSLayoutPriorityRequired.

Esempio: - UIButton vincoli con diverse priorità -

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]) 

     } 
+0

No, non dovresti mai creare vincoli in 'viewDidLayoutSubviews'. Quel metodo può essere chiamato più volte, il che può causare il crash della tua app se crei dei vincoli duplicati. – mph

+0

@mph true! ho modificato la risposta. – Jack