¿Cuándo se llama a layoutSubviews?

Resuelto Steve Weller asked hace 54 años • 8 respuestas

Tengo una vista personalizada que no recibe layoutSubviewmensajes 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. layoutSubviewsSe 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 layoutSubviewsno se llama en absoluto, aunque la vista principal anima su cambio de tamaño.

¿ En qué circunstancias se layoutSubviewsllama realmente?

Lo he autoresizesSubviewsconfigurado NOpara 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.

Steve Weller avatar Jan 01 '70 08:01 Steve Weller
Aceptado

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:

  • initno causa layoutSubviewsque lo llamen (duh)
  • addSubview:hace layoutSubviewsque 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 inteligente layoutSubviewsa la vista que tiene su marco configurado solo si el parámetro de tamaño del marco es diferente
  • desplazarse por un UIScrollView hace layoutSubviewsque se llame a scrollView y su supervista
  • rotar un dispositivo solo llama layoutSubviewa la vista principal (la vista principal de viewControllers que responde)
  • Cambiar el tamaño de una vista llamará layoutSubviewsa 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, llame layoutSubviewsa su supervisión )

Mis resultados: http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-call/

BadPirate avatar Mar 16 '2011 18:03 BadPirate

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.
Patrick Pijnappel avatar Oct 21 '2013 07:10 Patrick Pijnappel

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étodo setNeedsLayout o  layoutIfNeeded de una vista.
mi. Su aplicación fuerza el diseño llamando al  setNeedsLayout método del objeto de capa subyacente de la vista.

frogcjn avatar Sep 10 '2015 06:09 frogcjn

Algunos de los puntos de la respuesta de BadPirate son sólo parcialmente ciertos:

  1. por addSubViewpunto

    addSubviewhace 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.

  2. 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.

Mohit Nigam avatar Oct 29 '2012 11:10 Mohit Nigam

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.

Steve Weller avatar Apr 09 '2009 14:04 Steve Weller