Sé que la cadena de diseño automático consiste básicamente en 3 procesos diferentes.
- actualización de restricciones
- vistas de diseño (aquí es donde obtenemos el cálculo de los marcos)
- monitor
Lo que no está totalmente claro para mí 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 desee ajustar el diseño de las subvistas de una vista. Este método toma nota de la solicitud y regresa de inmediato. Debido a que este método no fuerza una actualización inmediata, sino que espera el próximo ciclo de actualización, puede usarlo para invalidar el diseño de varias vistas antes de que cualquiera de esas vistas se actualice. 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 afectaría las restricciones, puede llamar a este método para indicar que las restricciones deben actualizarse en algún momento en el futuro. El sistema luego llamará a updateConstraints como parte de su pase de diseño normal. La actualización de todas las restricciones de una vez, justo antes de que sean necesarias, garantiza que no recalcule innecesariamente las restricciones cuando se realizan múltiples cambios en su vista entre los 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 en -setNeedsLayout
lugar de que -setNeedsUpdateConstraints
todo funcione como se esperaba, pero si cambio -layoutIfNeeded
con -updateConstraintsIfNeeded
, la animación no sucederá.
Intenté llegar a 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 conserva-setNeedsLayout
también llama-updateContraints
método
Entonces, ¿cuándo está bien usar uno en lugar del otro? y sobre los métodos de diseño, ¿debo llamarlos en la vista que tiene un cambio en una restricción o en la vista principal?
Respuestas:
Tus conclusiones son correctas. El esquema básico es:
setNeedsUpdateConstraints
se asegura de una futura llamada aupdateConstraintsIfNeeded
llamadasupdateConstraints
.setNeedsLayout
se asegura de una futura llamada alayoutIfNeeded
llamadaslayoutSubviews
.Cuando
layoutSubviews
se llama, también llamaupdateConstraintsIfNeeded
, por lo que en mi experiencia rara vez se necesita llamarlo manualmente. De hecho, nunca lo he llamado, excepto al depurar diseños.setNeedsUpdateConstraints
También es bastante raro actualizar las restricciones usando , objc.io, una lectura obligada sobre autolayouts, dice :Además, en mi experiencia, nunca he tenido que invalidar restricciones, y no establecerlas
setNeedsLayout
en la siguiente línea del código, porque las nuevas restricciones están pidiendo un nuevo diseño.Las reglas generales son:
setNeedsLayout
.updateConstraints
método (un método recomendado a las restricciones de cambio, por cierto), llamadasetNeedsUpdateConstraints
, y la mayoría de las veces,setNeedsLayout
después de eso.layoutIfNeeded
.Además, en su código de animación, creo que no
setNeedsUpdateConstraints
es necesario, ya que las restricciones se actualizan antes de la animación manualmente, y la animación solo vuelve a mostrar la vista en función de las diferencias entre las antiguas y las nuevas.fuente
setNeedsLayout
.setNeedsLayout
se asegura delayoutSubviews
que se llamará en el próximo ciclo de actualización, pero ¿quizás esto no tenga nada que verlayoutIfNeeded
?layoutSubviews
te llamará automáticamente, no es necesario llamarsetNeedsLayout
layoutSubviews
, por lo que no es necesario hacerlo manualmente. Sin embargo, debe llamarlayoutIfNeeded
si necesita que los cambios surtan efecto de inmediato en lugar del próximo ciclo de diseñoLa respuesta del coverback es bastante correcta. Sin embargo, me gustaría agregar algunos detalles adicionales.
A continuación se muestra el diagrama de un ciclo típico de UIView que explica otros comportamientos:
-setNeedsLayout
lugar de que-setNeedsUpdateConstraints
todo funcione como se esperaba, pero si cambio-layoutIfNeeded
con-updateConstraintsIfNeeded
, la animación no sucederá.updateConstraints
normalmente no hace nada. Simplemente resuelve las restricciones, no las aplica hasta quelayoutSubviews
se llama. Entonces la animación requiere una llamada alayoutSubviews
.No, esto no es necesario. Si sus restricciones no se han modificado, UIView se saltará la llamada
updateConstraints
. Debe llamar explícitamentesetNeedsUpdateConstraint
para modificar las restricciones en el proceso.Para llamar
updateConstraints
necesita hacer lo siguiente:fuente