setNeedsLayout vs. setNeedsUpdateConstraints and layoutIfNeeded vs updateConstraintsIfNeeded

Sé que la cadena de diseño automático consiste básicamente en 3 procesos diferentes.

  1. actualización de restricciones
  2. vistas de diseño (aquí es donde obtenemos el cálculo de los marcos)
  3. monitor

Lo que no está totalmente claro para mí es la diferencia interna entre -setNeedsLayout y -setNeedsUpdateConstraints . De Apple Docs:

setNeedsLayout

Llame a este método en el hilo principal de su aplicación cuando desee ajustar el diseño de las subvistas de una vista. Este método toma nota de la solicitud y regresa inmediatamente. Como este método no obliga a una actualización inmediata, sino que espera el siguiente ciclo de actualización, puede usarlo para invalidar el diseño de varias vistas antes de que se actualice cualquiera de esas vistas. Este comportamiento le permite consolidar todas sus actualizaciones de diseño en un ciclo de actualización, que generalmente es mejor para el rendimiento.

setNeedsUpdateConstraints

Cuando una propiedad de su vista personalizada cambia de una manera que impacte las restricciones, puede llamar a este método para indicar que las restricciones deben actualizarse en algún momento en el futuro. El sistema llamará a updateConstraints como parte de su pase de diseño normal. Actualizar las restricciones de una vez, justo antes de que sean necesarias, garantiza que no recalcular innecesariamente las restricciones cuando se realizan varios cambios en la vista entre pases de diseño.

Cuando quiero animar una vista después de modificar una restricción y animar los cambios que suelo llamar, por ejemplo:

 [UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [self.modifConstrView setNeedsUpdateConstraints]; [self.modifConstrView layoutIfNeeded]; } completion:NULL]; 

Descubrí que si uso -setNeedsLayout lugar de -setNeedsUpdateConstraints todo funciona como se esperaba, pero si cambio -layoutIfNeeded con -updateConstraintsIfNeeded , la animación no ocurrirá.
Intenté hacer mi propia conclusión:

  • -updateConstraintsIfNeeded solo actualiza las restricciones, pero no obliga al diseño a entrar en el proceso, por lo tanto, los marcos originales aún se conservan
  • -setNeedsLayout llama también -updateContraints method

Entonces, ¿cuándo está bien usar uno en lugar del otro? y sobre los métodos de diseño, ¿necesito llamarlos en la vista que tiene un cambio en una restricción o en la vista principal?

Tus conclusiones son correctas. El esquema básico es:

  • setNeedsUpdateConstraints asegura que una futura llamada a updateConstraintsIfNeeded llame a updateConstraints .
  • setNeedsLayout se asegura de que una llamada futura a layoutIfNeeded llame a layoutSubviews .

Cuando se llama a updateConstraintsIfNeeded , también se llama a updateConstraintsIfNeeded , por lo que rara vez es necesario llamarlo manualmente. De hecho, nunca lo llamé, excepto al depurar diseños.

La actualización de restricciones usando setNeedsUpdateConstraints es bastante rara también, objc.io-a debe leer sobre autolayouts-dice :

Si algo cambia más adelante que invalide una de sus restricciones, debe eliminar la restricción inmediatamente y llamar a setNeedsUpdateConstraints. De hecho, ese es el único caso en el que debería tener que desencadenar un pase de actualización de restricciones.

Además, en mi experiencia, nunca he tenido que invalidar restricciones y no establecer setNeedsLayout en la siguiente línea del código, porque las nuevas restricciones prácticamente piden un nuevo diseño.

Las reglas generales son:

  • Si manipulaste restricciones directamente, llama a setNeedsLayout .
  • Si cambió algunas condiciones (como compensaciones o smth) que cambiarían las restricciones en su método reemplazado de updateConstraints (una forma recomendada de cambiar las restricciones, por cierto), llame a setNeedsUpdateConstraints , y la mayoría de las veces, setNeedsLayout después de eso.
  • Si necesita que alguna de las acciones anteriores tenga un efecto inmediato, por ejemplo, cuando necesite aprender una nueva altura de cuadro después de un pase de diseño, layoutIfNeeded con un layoutIfNeeded .

Además, en su código de animación, creo que setNeedsUpdateConstraints es necesario, ya que las restricciones se actualizan antes de la animación manualmente, y la animación solo vuelve a establecer la vista en función de las diferencias entre las antiguas y las nuevas.

La respuesta por cubierta es bastante correcta. Sin embargo, me gustaría agregar algunos detalles adicionales.

A continuación se muestra el diagtwig de un ciclo UIView típico que explica otros comportamientos Ciclo de vida de UIView

  1. Descubrí que si uso -setNeedsLayout en lugar de -setNeedsUpdateConstraints todo funciona como se esperaba, pero si cambio -layoutIfNeeded con -updateConstraintsIfNeeded, la animación no ocurrirá.

updateConstraints normalmente no hace nada. Simplemente resuelve restricciones, no las aplica hasta que se llama a layoutSubviews . Entonces la animación requiere una llamada a layoutSubviews .

  1. setNeedsLayout llama también -updateContraints method

No, esto no es necesario. Si sus restricciones no han sido modificadas, UIView omitirá la llamada a updateConstraints . Necesita llamar explícitamente a setNeedsUpdateConstraint para modificar las restricciones en el proceso.

Para llamar a updateConstraints , debe hacer lo siguiente:

  [view setNeedsUpdateConstraints]; [view setNeedsLayout]; [view layoutIfNeeded];