ios - sola - enableConstraints: y deactivateConstraints: no persisten después de la rotación para las restricciones creadas en IB
la pantalla de mi iphone se mueve sola (3)
Los nuevos métodos NSLayoutConstraint
activateConstraints:
y deactivateConstraints:
no parecen funcionar correctamente con las restricciones creadas por el IB (funcionan correctamente para las restricciones creadas con código). Creé una aplicación de prueba simple con un botón que tiene dos conjuntos de restricciones. Un conjunto, que está instalado, tiene restricciones centerX y centerY, y el otro conjunto, que se desinstala, tiene restricciones superiores e izquierdas (constante 10). El método del botón cambia estos conjuntos de restricciones. Aquí está el código,
@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");
}
Cuando se inicia la aplicación, el botón se encuentra en la posición correcta y centrada definida por sus restricciones instaladas. Después de realizar la activación / desactivación en el método de acción del botón, el botón se mueve a su nueva posición correctamente, pero cuando giro la vista a horizontal, vuelve a su posición definida inicialmente (aunque un registro aún muestra el conjunto recién activado como estando activo). Cuando vuelvo a la posición vertical, el botón permanece en su posición inicial (centrado en la pantalla), y ahora el registro muestra que el conjunto inicial de restricciones está activo y las que activé, como inactivas.
La pregunta es: ¿se trata de un error, o se supone que estos métodos no funcionan de esta manera con restricciones definidas por el IB?
El problema es que estás haciendo algo incoherente con restricciones "desinstaladas" en el guión gráfico. Están ahí pero no están allí. ¡Las restricciones "desinstaladas" se usan solo con clases de tamaño! Puede usarlos si va a permitir que Xcode cambie las restricciones automáticamente en la rotación. Xcode no puede hacer frente a lo que estás haciendo. Pero si creas el segundo conjunto de restricciones en el código, todo funcionará bien.
Entonces, haz esto. Elimine las dos restricciones "desinstaladas" y elimine la salida uninstalledConstraints
. Ahora reemplace el código completo de su controlador de vista con esto:
@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;
}
Ahora presione repetidamente el botón. Como ves, salta entre las dos posiciones. Ahora rota la aplicación; el botón se queda donde está.
Me enfrenté a una situación similar.
Creé dos conjuntos de NSLayoutConstraints en el constructor de interfaces. Cada conjunto para un caso. Un conjunto fue "instalado" el otro no.
Cuando cambio el caso, se activó el conjunto correspondiente de restricción de diseño y el otro se desactivó. Y como se describe en el Qusteion que gira hacia adelante y hacia atrás, no funciona correctamente.
Se soluciona esto instalando ambos conjuntos en el constructor de interfaces. Y para deshacerme de las advertencias, utilicé una prioridad ligeramente inferior (999) para el segundo set. Esto funcionó para mí.
Por cierto: Strang, utilicé el enfoque "instalado / no instalado" en otro controlador de vista, funcionó.
En el caso de que no funcionara, el controlador de vista estaba incrustado en una vista de contenido, tal vez esa fue la razón.
Puede usar este flujo de trabajo, aunque está claro que este no es un caso de uso compatible actualmente para la gente de Apple.
El truco es no desinstalar las restricciones (como también lo señaló @matt), sino desactivarlas en la viewDidLoad()
de su subclase UIViewController
, antes de que ocurra el diseño (y sus restricciones en conflicto causan un problema).
Estoy usando ese método ahora y funciona perfectamente. Lo ideal sería, por supuesto, tener la capacidad de crear visualmente grupos de restricciones y usarlos como fotogramas clave simplemente activándolos y desactivándolos (con animaciones gratuitas en el medio) :)