¿Cuándo se llama a layoutSubviews?
Tengo una vista personalizada que no recibe layoutSubview
mensajes durante la animación.
Tengo una vista que llena la pantalla. Tiene una subvista personalizada en la parte inferior de la pantalla que cambia de tamaño correctamente en Interface Builder si cambio la altura de la barra de navegación. layoutSubviews
Se llama cuando se crea la vista, pero nunca más. Mis subvistas están diseñadas correctamente. Si desactivo la barra de estado de la llamada, la subvista layoutSubviews
no se llama en absoluto, aunque la vista principal anima su cambio de tamaño.
¿ En qué circunstancias se layoutSubviews
llama realmente?
Lo he autoresizesSubviews
configurado NO
para mi vista personalizada. Y en Interface Builder tengo configurados los puntales superior e inferior y la flecha vertical.
Otra parte del rompecabezas es que la ventana debe ser clave:
[window makeKeyAndVisible];
De lo contrario, las subvistas no cambian de tamaño automáticamente.
Tenía una pregunta similar, pero no estaba satisfecho con la respuesta (ni con ninguna que pudiera encontrar en la red), así que lo intenté en la práctica y esto es lo que obtuve:
init
no causalayoutSubviews
que lo llamen (duh)addSubview:
hacelayoutSubviews
que se llame a la vista que se agrega, a la vista a la que se agrega (vista de destino) y a todas las subvistas del objetivo- La vista
setFrame
llama de forma inteligentelayoutSubviews
a la vista que tiene su marco configurado solo si el parámetro de tamaño del marco es diferente - desplazarse por un UIScrollView hace
layoutSubviews
que se llame a scrollView y su supervista - rotar un dispositivo solo llama
layoutSubview
a la vista principal (la vista principal de viewControllers que responde) - Cambiar el tamaño de una vista llamará
layoutSubviews
a su supervista ( Importante: las vistas con un tamaño de contenido intrínseco cambiarán de tamaño si el contenido que determina su tamaño cambia; por ejemplo, actualizar el texto en una UILabel hará que se actualice el tamaño del contenido intrínseco y, por lo tanto, llamelayoutSubviews
a su supervisión )
Mis resultados: http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-call/
Basándome en la respuesta anterior de @BadPirate, experimenté un poco más y se me ocurrieron algunas aclaraciones/correcciones. Descubrí que layoutSubviews:
se llamará a una vista si y solo si:
- Sus propios límites (no marco) cambiaron.
- Los límites de una de sus subvistas directas cambiaron.
- Se agrega una subvista a la vista o se elimina de ella.
Algunos detalles relevantes:
- Los límites se consideran modificados solo si el nuevo valor es diferente, incluido un origen diferente . Tenga en cuenta específicamente que es por eso
layoutSubviews:
que se llama cada vez que se desplaza un UIScrollView, ya que realiza el desplazamiento cambiando el origen de sus límites. - Cambiar el marco solo cambiará los límites si el tamaño ha cambiado, ya que esto es lo único que se propaga a la propiedad de límites.
- Un cambio en los límites de una vista que aún no está en una jerarquía de vistas resultará en una llamada
layoutSubviews:
cuando la vista finalmente se agregue a una jerarquía de vistas . - Y solo para completar: estos activadores no llaman directamente a layoutSubviews, sino que llaman a
setNeedsLayout
, lo que establece/levanta una bandera. En cada iteración del ciclo de ejecución, para todas las vistas en la jerarquía de vistas , se marca este indicador. Por cada vista donde se encuentre la bandera izada,layoutSubviews:
se llama a ella y se reinicia la bandera. Las vistas que se encuentran más arriba en la jerarquía se verificarán/llamarán primero.
https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1
Los cambios de diseño pueden ocurrir siempre que ocurra cualquiera de los siguientes eventos en una vista:
a. El tamaño del rectángulo de límites de una vista cambia.
b. Se produce un cambio de orientación de la interfaz, que normalmente desencadena un cambio en el rectángulo de límites de la vista raíz.
C. El conjunto de subcapas de Core Animation asociadas con la capa de la vista cambia y requiere diseño.
d. Su aplicación fuerza que se produzca el diseño llamando al métodosetNeedsLayout
olayoutIfNeeded
de una vista.
mi. Su aplicación fuerza el diseño llamando alsetNeedsLayout
método del objeto de capa subyacente de la vista.
Algunos de los puntos de la respuesta de BadPirate son sólo parcialmente ciertos:
por
addSubView
puntoaddSubview
hace que se llame a layoutSubviews en la vista que se agrega, la vista a la que se agrega (vista de destino) y todas las subvistas del destino.Depende de la máscara de tamaño automático de la vista (vista de destino). Si tiene la máscara de tamaño automático activada, se llamará a layoutSubview en cada archivo
addSubview
. Si no tiene una máscara de tamaño automático, se llamará a layoutSubview solo cuando cambie el tamaño del marco de la vista (Vista de destino).Ejemplo: si creó UIView mediante programación (no tiene máscara de tamaño automático de forma predeterminada), se llamará a LayoutSubview solo cuando el marco de UIView cambie, no en cada archivo
addSubview
.Es a través de esta técnica que también aumenta el rendimiento de la aplicación.
Para el punto de rotación del dispositivo
Al girar un dispositivo, solo se llama a layoutSubview en la vista principal (la vista principal del viewController que responde)
Esto puede ser cierto solo cuando su VC está en la jerarquía de VC (raíz en
window.rootViewController
), bueno, este es el caso más común. En iOS 5, si crea un VC, pero no se agrega a ningún otro VC, este VC no se notará cuando el dispositivo gire. Por lo tanto, su vista no se notará al llamar a layoutSubviews.
Seguí la solución hasta la insistencia de Interface Builder de que los resortes no se pueden cambiar en una vista que tiene los elementos de pantalla simulados activados (barra de estado, etc.). Dado que los resortes estaban desactivados para la vista principal, esa vista no podía cambiar de tamaño y, por lo tanto, se desplazaba hacia abajo en su totalidad cuando aparecía la barra de llamadas entrantes.
Desactivar las funciones simuladas, luego cambiar el tamaño de la vista y configurar los resortes correctamente provocó que se produjera la animación y se llamara a mi método.
Un problema adicional al depurar esto es que el simulador sale de la aplicación cuando el estado de la llamada entrante se alterna a través del menú. Salir de la aplicación = sin depurador.