ios - top - nslayoutconstraint swift 4
setNeedsLayout vs. setNeedsUpdateConstraints y layoutIfNeeded vs updateConstraintsIfNeeded (2)
Sé que la cadena de diseño automático consiste básicamente en 3 procesos diferentes.
- restricciones de actualización
- Vistas de diseño (aquí es donde obtenemos el cálculo de los marcos)
- monitor
Lo que no me queda totalmente claro es la diferencia interna entre -setNeedsLayout
y -setNeedsUpdateConstraints
. De Apple Docs:
Llame a este método en el hilo principal de su aplicación cuando quiera ajustar el diseño de las subvistas de una vista. Este método toma nota de la solicitud y devuelve inmediatamente. Debido a que este método no fuerza 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.
Cuando una propiedad de su vista personalizada cambia de una manera que podría afectar 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 sola vez, justo antes de que sean necesarias, garantiza que no vuelva a calcular las restricciones innecesariamente cuando se realicen múltiples cambios en su vista entre las pasadas de diseño.
Cuando quiero animar una vista después de modificar una restricción y animar los cambios, generalmente llamo 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 espera, pero si cambio -layoutIfNeeded
con -updateConstraintsIfNeeded
, la animación no sucederá.
He intentado llegar a mi propia conclusión:
-
-updateConstraintsIfNeeded
solo actualiza las restricciones pero no obliga a que el diseño-updateConstraintsIfNeeded
al proceso, por lo tanto, los cuadros originales aún se conservan -
-setNeedsLayout
también llama-updateContraints
método-updateContraints
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?
La respuesta por coverback es bastante correcta. Sin embargo, me gustaría añadir algunos detalles adicionales.
A continuación se muestra el diagrama de un ciclo UIView típico que explica otros comportamientos:
- Descubrí que si uso
-setNeedsLayout
lugar de-setNeedsUpdateConstraints
todo funciona como se espera, pero si cambio-layoutIfNeeded
con-updateConstraintsIfNeeded
, la animación no sucederá.
updateConstraints
normalmente no hace nada. Simplemente resuelve las restricciones, no las aplica hasta que se llama layoutSubviews
. Así que la animación requiere una llamada a layoutSubviews
.
- setNeedsLayout también llama al método -updateContraints
No, esto no es necesario. Si sus restricciones no se han modificado, UIView saltará la llamada a updateConstraints
. setNeedsUpdateConstraint
llamar explícitamente a setNeedsUpdateConstraint
para modificar las restricciones en el proceso.
Para llamar a updateConstraints
necesitas hacer lo siguiente:
[view setNeedsUpdateConstraints];
[view setNeedsLayout];
[view layoutIfNeeded];
Tus conclusiones son correctas. El esquema básico es:
-
setNeedsUpdateConstraints
se asegura de una futura llamada aupdateConstraintsIfNeeded
llama aupdateConstraints
. -
setNeedsLayout
se asegura de una futura llamada alayoutIfNeeded
llamadaslayoutSubviews
.
Cuando se llama a updateConstraintsIfNeeded
, también se llama a updateConstraintsIfNeeded
, por lo que llamarlo manualmente rara vez es necesario en mi experiencia. De hecho, nunca lo he llamado, excepto al depurar diseños.
La actualización de restricciones usando setNeedsUpdateConstraints
es bastante rara, objc.io, una lectura obligada sobre los autolayouts, dice :
Si algo cambia más adelante que invalida 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 activar un paso de actualización de restricción.
Además, en mi experiencia, nunca he tenido que invalidar las restricciones y no establecer setNeedsLayout
en la siguiente línea del código, porque las nuevas restricciones casi setNeedsLayout
un nuevo diseño.
Las reglas de oro son:
- Si manipuló las restricciones directamente, llame a
setNeedsLayout
. - Si cambió algunas condiciones (como compensaciones o smth) que cambiarían las restricciones en su método de
updateConstraints
invalidado (una forma recomendada de cambiar las restricciones, por cierto), llame asetNeedsUpdateConstraints
y la mayoría de las veces,setNeedsLayout
después de eso. - Si necesita alguna de las acciones anteriores para tener un efecto inmediato, por ejemplo, cuando necesite aprender una nueva altura de marco después de un pase de diseño,
layoutIfNeeded
con unlayoutIfNeeded
.
Además, en su código de animación, creo que setNeedsUpdateConstraints
es necesario, ya que las restricciones se actualizan manualmente antes de la animación, y la animación solo re-establece la vista en función de las diferencias entre la antigua y la nueva.