No estoy hablando de la propiedad del marco, porque a partir de eso solo puede obtener el tamaño de la vista en el xib. Estoy hablando de cuándo se cambia el tamaño de la vista debido a sus limitaciones (tal vez después de una rotación o en respuesta a un evento). ¿Hay alguna forma de obtener su ancho y alto actuales?
Intenté iterar a través de sus restricciones buscando restricciones de ancho y alto, pero eso no es muy limpio y falla cuando hay restricciones intrínsecas (ya que no puedo diferenciar entre las dos). Además, eso solo funciona si realmente tienen restricciones de ancho y alto, lo que no es así si dependen de otras restricciones para cambiar el tamaño.
¿Por qué esto es tan difícil para mí? ARG!
ios
autolayout
yuf
fuente
fuente
Respuestas:
La respuesta es
[view layoutIfNeeded]
.Este es el por qué:
Aún obtiene el ancho y alto actuales de la vista al inspeccionar
view.bounds.size.width
yview.bounds.size.height
(o el marco, que es equivalente a menos que esté jugando conview.transform
).Si lo que desea es el ancho y la altura implícitos en sus restricciones existentes, la respuesta no es inspeccionar las restricciones manualmente, ya que eso requeriría que vuelva a implementar toda la lógica de resolución de restricciones del sistema de diseño automático para interpretarlas. limitaciones. En su lugar, lo que debe hacer es simplemente pedirle a auto layout que actualice ese diseño , de modo que resuelva las restricciones y actualice el valor de view.bounds con la solución correcta, y luego inspeccione view.bounds.
¿Cómo le pides al diseño automático que actualice el diseño? Llame
[view setNeedsLayout]
si desea que el diseño automático actualice el diseño en el siguiente giro del ciclo de ejecución.Sin embargo, si desea que actualice el diseño de inmediato, para que pueda acceder inmediatamente al nuevo valor de límites más adelante dentro de su función actual, o en otro punto antes del turno del ciclo de ejecución, entonces debe llamar
[view setNeedsLayout]
y[view layoutIfNeeded]
.Hiciste una segunda pregunta: "¿cómo puedo cambiar una restricción de altura / ancho si no tengo una referencia a ella directamente?".
Si crea la restricción en IB, la mejor solución es crear un IBOutlet en su controlador de vista o en su vista para que tenga una referencia directa a él. Si creó la restricción en el código, entonces debe mantener una referencia en una propiedad débil interna en el momento en que la creó. Si alguien más creó la restricción, entonces debe encontrarla examinando la propiedad view.constraints en la vista, y posiblemente toda la jerarquía de la vista, e implementando la lógica que encuentra la NSLayoutConstraint crucial. Este es probablemente el camino equivocado, ya que también requiere que usted determine qué restricción particular determinó el tamaño de los límites, cuando no se garantiza que haya una respuesta simple a esa pregunta. El valor de los límites finales podría ser la solución a un sistema muy complicado de restricciones múltiples,
fuente
layoutIfNeeded
es genial y hará que el marco esté disponible de inmediato. Sin embargo, también forzará la representación de las restricciones en todas las vistas en los subárboles de la vista en la que se llama. Si está agregando vistas mediante programación, por ejemplo, y las llamalayoutIfNeeded
a todas en su rutina recursiva, puede encontrar que su jerarquía de vistas se representa muy lentamente. (Aprendí esto de la manera difícil) Como se mencionó en la excelente respuesta, 'setNeedsLayout` es más eficiente y hará que el marco esté disponible en la siguiente pasada de diseño, lo que idealmente ocurre en aproximadamente 1/60 de segundo.initWithCoder
?Tuve un problema similar en el que necesitaba agregar un borde superior e inferior a un
UITableView
tamaño que cambia según su configuración de restricciones enUIStoryboard
. Pude acceder a las restricciones actualizadas con- (void)viewDidLayoutSubviews
. Esto es útil para que no necesite crear una subclase de una vista y anular su método de diseño.Sin llamar al método desde el
viewDidLayoutSubview
método, solo el borde superior se dibuja correctamente, ya que el borde inferior está en algún lugar fuera de la pantalla.fuente
[super viewDidLayoutSubviews];
Para aquellos que todavía pueden estar enfrentando tales problemas, especialmente con TableviewCell.
Simplemente anule el método:
En el caso de UITableViewCell o UICollectionViewCell, cree una subclase de la celda y anule el mismo método:
fuente
Usar
-(void)viewWillAppear:(BOOL)animated
y llamar[self.view layoutIfNeeded];
- Funciona, lo he probado.porque si lo usa
-(void)viewDidLayoutSubviews
, definitivamente funcionará, pero este método se llama cada vez que su interfaz de usuario exige actualizaciones / cambios. Lo cual será difícil de manejar. La tecla programable es que usa una variable bool para evitar ese bucle de llamadas. mejor usoviewWillAppear
.viewWillAppear
También se llamará a Remember si la vista se vuelve a cargar (sin reasignar).fuente
El marco sigue siendo válido. Al final, la vista usa su propiedad de marco para distribuirse. Calcula ese marco en función de todas las restricciones. Las restricciones solo se utilizan para el diseño inicial (y en cualquier momento se llama a layoutSubviews en una vista como después de una rotación). Después de eso, la información de la posición está en la propiedad del marco. ¿O estás viendo lo contrario?
fuente