¿Cuándo puedo activar / desactivar las restricciones de layout?

He configurado varios sets de restricciones en IB, y me gustaría alternar entre ellos dependiendo de algún estado mediante progtwigción. Hay una colección de salidas de constraintsA , todas las cuales están marcadas como instaladas de IB, y una colección de salidas de constraintsB B, todas las cuales se desinstalan en IB.

Puedo progtwigr alternar entre los dos sets de la siguiente manera:

 NSLayoutConstraint.deactivateConstraints(constraintsA) NSLayoutConstraint.activateConstraints(constraintsB) 

Pero … no puedo imaginar cuándo hacer eso. Parece que debería poder hacer eso una vez en viewDidLoad , pero no puedo hacer que funcione. Intenté llamar a view.updateConstraints() y view.layoutSubviews() después de establecer las restricciones, pero fue en vano.

Descubrí que si establecía las restricciones en viewDidLayoutSubviews todo funciona como se esperaba. Supongo que me gustaría saber dos cosas …

  1. ¿Por qué tengo este comportamiento?
  2. ¿Es posible activar / desactivar las restricciones de viewDidLoad?

Activar y desactivar NSLayoutConstraints en viewDidLoad , y no tengo ningún problema con él. Entonces funciona. Debe haber una diferencia en la configuration entre su aplicación y la mía 🙂

Simplemente describiré mi configuration, tal vez te pueda dar una pista:

  1. Configuré @IBOutlets para todas las restricciones que necesito para activar / desactivar.
  2. En ViewController , ViewController las restricciones en properties de class que no son débiles. La razón de esto es que encontré que después de desactivar una restricción, no podía reactivarla, era nula. Por lo tanto, parece que se elimina cuando se desactiva.
  3. No uso NSLayoutConstraint.deactivate/activate como lo hago, uso constraint.active = YES / NO lugar.
  4. Después de establecer las restricciones, llamo a view.layoutIfNeeded() .
 override func viewDidLayoutSubviews() { // do it here, after constraints have been materialized } 

Tal vez pueda verificar sus @properties , reemplace weak con strong .

A veces, porque active = NO establece self.yourContraint = nil , por lo que no puede usar self.yourContraint nuevamente.

Creo que el problema que está experimentando se debe a que no se agregan restricciones a sus vistas hasta que se viewDidLoad() DESPUÉS de viewDidLoad() . Tienes un número de opciones:

A) Puede conectar sus restricciones de layout a un IBOutlet y acceder a ellas en su código mediante estas references. Dado que las salidas están conectadas antes de que se viewDidLoad() , las restricciones deben ser accesibles y puede continuar activándolas y desactivándolas allí.

B) Si desea utilizar la function de constraints() UIView para acceder a las diversas restricciones, debe esperar a que viewDidLayoutSubviews() y lo haga allí, ya que es el primer punto después de crear un controller de vista desde una punta que tendrá cualquier restricción instalada. No olvides llamar a layoutIfNeeded() cuando hayas terminado. Esto tiene la desventaja de que el pase de layout se realizará dos veces si hay algún cambio que aplicar y debe asegurarse de que no hay posibilidad de que se active un ciclo infinito.

Una palabra rápida de advertencia: ¡las restricciones deshabilitadas NO son devueltas por el método constraints() ! Esto significa que si DESHABILITA una restricción con la intención de volverla a encender más tarde, necesitará mantener una reference a la misma.

C) Puede olvidarse del enfoque de storyboard y agregar sus restricciones manualmente. Dado que está haciendo esto en viewDidLoad() , supongo que la intención es hacerlo solo una vez durante toda la vida útil del object en lugar de cambiar el layout sobre la marcha, por lo que este debería ser un método aceptable.

También puede ajustar la propiedad de priority para "habilitar" y "deshabilitar" (750 valores para habilitar y 250 para deshabilitar, por ejemplo). Por alguna razón, cambiar el BOOL active no tuvo ningún efecto en mi UI. No hay necesidad de layoutIfNeeded y se puede configurar y cambiar en viewDidLoad o en cualquier momento posterior.

El momento adecuado para desactivar las restricciones no utilizadas:

 -(void)viewWillLayoutSubviews{ [super viewWillLayoutSubviews]; self.myLittleConstraint.active = NO; } 

Tenga en count que viewWillLayoutSubviews podría llamar varias veces, por lo que no hay cálculos pesados ​​aquí, ¿está bien?

Nota: si desea reactivar algunas de las restricciones más adelante, entonces siempre guarde una strong reference a ellas.

He encontrado siempre que configuras las restricciones por normal en la anulación de - (void)updateConstraints (objective c), con una strong reference para las restricciones activas y no activas iniciales. Y en cualquier otro lugar del ciclo de vista, desactive y / o active lo que necesita, luego, llamando a layoutIfNeeded , no debería tener problemas.

Lo principal es no reutilizar constantemente la anulación de updateConstraints y separar las activaciones de las restricciones, siempre que llame a updateConstraint s después de su primera initialization y layout. Parece importante después de eso, en el ciclo de vista.

Cuando se crea una vista, se invocan los siguientes methods de ciclo de vida en order:

  1. loadView
  2. viewDidLoad
  3. viewWillAppear
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews
  6. viewDidAppear

Ahora a sus preguntas.

  1. ¿Por qué tengo este comportamiento?

Respuesta: porque cuando intenta establecer las restricciones en las vistas en viewDidLoad la vista no tiene sus límites, por lo tanto, las restricciones no se pueden establecer. Solo después de viewDidLayoutSubviews , los límites de la vista están finalizados.

  1. ¿Es posible activar / desactivar las restricciones de viewDidLoad?

Respuesta: No. Motivo explicado anteriormente.