2014-12-27 7 views
24

I nuovi metodi NSLayoutConstraintactivateConstraints: e deactivateConstraints: non sembrano funzionare correttamente con i vincoli IB-create (che funzionano correttamente per vincoli di codici creati). Ho creato una semplice app di test con un pulsante con due serie di vincoli. Un set, che è installato, ha vincoli centerX e centerY e l'altro set, che viene disinstallato, ha vincoli top e left (costante 10). Il metodo button cambia questi set di vincoli. Ecco il codice,activateConstraints: e deactivateConstraints: non persistono dopo la rotazione dei vincoli creati in IB

@interface ViewController() 
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *uninstalledConstraints; 
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints; 
@end 

@implementation ViewController 


- (IBAction)switchconstraints:(UIButton *)sender { 
    [NSLayoutConstraint deactivateConstraints:self.installedConstraints]; 
    [NSLayoutConstraint activateConstraints:self.uninstalledConstraints]; 
} 


-(void)viewWillLayoutSubviews { 
    NSLog(@"installed: %@ uninstalled: %@", ((NSLayoutConstraint *)self.installedConstraints[0]).active ? @"Active" : @"Inactive", ((NSLayoutConstraint *)self.uninstalledConstraints[0]).active ? @"Active" : @"Inactive"); 

} 

Quando i lanci app, il pulsante è nella posizione corretta, centrato definito dai suoi vincoli installati. Dopo aver eseguito l'attivazione/disattivazione nel metodo di azione del pulsante, il pulsante si sposta correttamente nella sua nuova posizione, ma quando ruoto la vista in orizzontale, torna alla posizione inizialmente definita (sebbene un registro mostri ancora il set appena attivato come essere attivo). Quando ruoto di nuovo in verticale, il pulsante rimane nella sua posizione iniziale (centrato sullo schermo), e ora il registro mostra che l'insieme iniziale di vincoli come attivi e quelli che ho attivato, come inattivi.

La domanda è, si tratta di un bug o questi metodi non dovrebbero funzionare in questo modo con i vincoli definiti da IB?

+0

Oooooh, bene, ora stiamo scendendo a puntine di ottone. Puoi pubblicare il progetto su github? Non vedevo l'ora. – matt

+0

@matt, ecco il link, http://jmp.sh/GWIN1Bg – rdelmar

+0

Giusto, ma non è così perché quello che stai facendo con i vincoli di disinstallato nello storyboard con uno sbocco a loro è incoerente? – matt

risposta

22

Il problema è che si sta facendo qualcosa di incoerente con i vincoli "disinstallati" nello storyboard. Sono lì ma non là. I vincoli "disinstallati" possono essere utilizzati solo con classi di dimensioni! Li usi se hai intenzione di lasciare vincoli di scambio Xcode per te automaticamente su a rotazione. Xcode non può far fronte a quello che stai facendo. Ma se crei il secondo set di vincoli nel codice, tutto funzionerà correttamente.

Quindi, fatelo. Eliminare i due vincoli "disinstallati" ed eliminare la presa uninstalledConstraints. Ora sostituisci l'intero codice del controller di visualizzazione con questo:

@property (strong, nonatomic) NSMutableArray *c1; 
@property (strong, nonatomic) NSMutableArray *c2; 
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints; 
@property (weak,nonatomic) IBOutlet UIButton *button; 
@end 

@implementation ViewController { 
    BOOL did; 
} 

- (void)viewDidLayoutSubviews { 
    NSLog(@"did"); 
    if (!did) { 
     did = YES; 
     self.c1 = [self.installedConstraints mutableCopy]; 
     self.c2 = [NSMutableArray new]; 
     [self.c2 addObject: 
     [NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1 constant:30]]; 
     [self.c2 addObject: 
     [NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeadingMargin multiplier:1 constant:30]]; 
    } 
} 

- (IBAction)switchconstraints:(UIButton *)sender { 
    [NSLayoutConstraint deactivateConstraints:self.c1]; 
    [NSLayoutConstraint activateConstraints:self.c2]; 
    NSMutableArray* temp = self.c1; 
    self.c1 = self.c2; 
    self.c2 = temp; 
} 

Ora premere ripetutamente il pulsante. Come vedi, salta tra le due posizioni. Ora ruota l'app; il pulsante rimane dov'è.

+0

Scusa, ho perso la parte di Github. Non hai davvero bisogno di pubblicare alcun codice, l'unica frase, i vincoli "Disinstallati" sono per noi solo con le classi di dimensioni! "Sarebbe stato sufficiente. Sarebbe bello sapere dove è documentato. I video WWDC stanno cercando di trovare qualcosa su activateConstraints/deactivateConstraints.La documentazione su di essi è piuttosto sottile – rdelmar

+1

Il fatto è che è tutto totalmente ortogonale L'attivazione/disattivazione non ha nulla a che fare con il problema dei vincoli disinstallati. gran parte di un disastro se avessi usato 'removeConstraints' e' addConstraints'. Erano i vincoli disinstallati con lo sbocco che stava uccidendo tutto.Uso dei vincoli installati/disinstallati con classi di dimensioni multiple è molto ben documentato, questo è quello che loro Lo so che è deludente che non si possano disegnare entrambi i gruppi di vincoli nello storyboard, ma eccolo. – matt

+3

Ho visto la documentazione per l'installazione di un Disinstallare i vincoli con le classi di dimensioni, ma ciò che mi sembrava di aver perso è una spiegazione fondamentale di ciò che significa che un vincolo deve essere "installato" o "disinstallato". Quindi, la mia (errata) comprensione era che un vincolo disinstallato era l'equivalente IB di creare un vincolo nel codice, ma non aggiungerlo alla vista. Puoi indicarmi dove questo concetto è ben documentato? – rdelmar

10

Ho affrontato una situazione simile.

Ho creato due set di NSLayoutConstraints nel builder dell'interfaccia. Ogni set per un caso. Un set è stato "installato" l'altro no.

Quando si passa al caso è stato attivato il set corrispondente di vincolo di layout e l'altro è stato disattivato. Un come descritto nel Qusteion ruotando avanti e indietro non funziona correttamente.

È risolto installando entrambi i set nel generatore di interfacce. E per eliminare gli avvertimenti ho usato una priorità leggermente più bassa (999) per il secondo set. Questo ha funzionato per me.

Btw: Strang ho usato l'aproach "installato/non installato" su un altro viewcontroller, hanno funzionato.

Nel caso non funzionante, il viewcontroller era incorporato in un container, forse era questo il motivo.

+0

3 agosto 16, ho svitato questa risposta. 21 giugno 17, non posso revocarlo due volte :( –

+0

Inoltre, se rimuovi il containerview dalla sua superview, ritorna dopo la rotazione dello schermo, davvero misterioso: P si spera che Apple risolverà questi difetti presto –

2

È possibile utilizzare questo flusso di lavoro, anche se è chiaro che questo non è un caso di utilizzo attualmente supportato per la gente di Apple.

Il trucco è quello di non vincoli di disinstallazione (come @ Matt ha anche sottolineato), ma di disattivare in viewDidLoad() del vostro UIViewController sottoclasse, prima che si verifichi il layout (e vostri vincoli conflittuali causare un problema).

Ora sto usando questo metodo e funziona perfettamente. Idealmente, naturalmente, avremmo la possibilità di creare visivamente gruppi di vincoli e usarli come keyframe semplicemente attivandoli e disattivandoli (con animazioni gratuite tra) :)

Problemi correlati