¿Cuándo se llama layoutSubviews?


Tengo una vista personalizada que no recibe layoutSubview mensajes durante la animación.

Tengo una vista que llena la pantalla. Tiene una vista secundaria personalizada en la parte inferior de la pantalla que cambia el 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 subviews están correctamente establecidos. Si desactivo la barra de estado de la llamada, el subview layoutSubviews no se llama en absoluto, a pesar de que la vista principal anima su redimensionar.

¿Bajo qué circunstancias se llama layoutSubviews realmente?

Tengo autoresizesSubviews establecido en NO para mi vista personalizada. Y en Interface Builder tengo los puntales superior e inferior y el conjunto de flechas verticales.

Author: Honey, 2009-04-08

10 answers

Tenía una pregunta similar, pero no estaba satisfecho con la respuesta (o cualquiera que pudiera encontrar en la red), así que lo intenté en la práctica y esto es lo que obtuve:

  • init no causa que layoutSubviews ser llamado (duh)
  • addSubview: causas layoutSubviews para ser llamado a la punto de vista agregado, la vista se añadido a (vista de destino), y todos los subviews of the target
  • ver setFrame llama inteligentemente layoutSubviews en la vista que tiene su marco establecido solamente si el parámetro tamaño del marco ser diferente
  • desplazando un UIScrollView causas layoutSubviews para ser llamado el ScrollView, y su superview
  • rotar un dispositivo solo llama layoutSubview en la vista padre (el responding ViewController primary vista)
  • Cambiar el tamaño de una vista llamará a layoutSubviews en su supervisión

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

 450
Author: BadPirate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-03 09:07:17

Basándome en la respuesta anterior de @BadPirate, experimenté un poco más y se me ocurrieron algunas aclaraciones/correcciones. Encontré que layoutSubviews: será llamado en una vista si y solo si:

  • Sus propios límites (no marco) cambiado.
  • Los límites de una de sus subviews directas cambiaron.
  • Se agrega una subvista a la vista o se elimina de la vista.

Algunos detalles relevantes:

  • Los límites se consideran cambiados solo si el nuevo el valor es diferente, incluyendo un origen diferente. Tenga en cuenta específicamente que es por eso que layoutSubviews: se llama cada vez que un desplazamiento de 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 bounds.
  • Un cambio en los límites de una vista que aún no está en una jerarquía de vista resultará en una llamada a layoutSubviews: cuando la vista se agrega finalmente a un ver jerarquía .
  • Y solo para completar: estos disparadores no llaman directamente a layoutSubviews, sino que llaman setNeedsLayout, lo que establece/eleva una bandera. Cada iteración del bucle de ejecución, para todas las vistas en la jerarquía de vistas, este indicador está marcado. Para cada vista en la que se encuentra el indicador elevado, se llama a layoutSubviews: y se restablece el indicador. Las vistas superiores a la jerarquía serán verificadas / llamadas primero.
 60
Author: Patrick Pijnappel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-06 01:07:48

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 un punto de 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 generalmente desencadena un cambio en el rectángulo de límites de la vista raíz.
c. The el conjunto de subcapas principales de animación asociadas con la capa de la vista cambia y requiere diseño.
d. Su aplicación obliga a que se produzca el layout llamando al método setNeedsLayout o layoutIfNeeded de una vista.
e. Su aplicación fuerza el layout llamando al método setNeedsLayout del objeto de capa subyacente de la vista.

 13
Author: frogcjn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-16 02:09:09

Algunos de los puntos en La respuesta de BadPirate son solo parcialmente ciertos:

  1. Para addSubView punto

    addSubview hace que layoutSubviews se invoque en la vista que se agrega, en la vista a la que se agrega (vista de destino) y en todas las subviews del destino.

    Depende de la máscara de autoresize de la vista (vista de destino). Si tiene la máscara autoresize ACTIVADA, layoutSubview será llamada en cada addSubview. Si no tiene máscara de tamaño automático, entonces layoutSubview será se llama solo cuando cambia el tamaño del marco de la vista (vista de destino).

    Ejemplo: si ha creado UIView programáticamente (no tiene máscara de autoresize por defecto), layoutSubview solo se llamará cuando el marco UIView cambie, no en cada addSubview.

    Es a través de esta técnica que el rendimiento de la aplicación también aumenta.

  2. Para el punto de rotación del dispositivo

    Rotar un dispositivo solo llama a layoutSubview en la vista padre (la respuesta Vista primaria de ViewController)

    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ía llamando a layoutSubviews.

 9
Author: Mohit Nigam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:45

Llamando [self.view setNeedsLayout]; en ViewController hace que llame a viewDidLayoutSubviews

 7
Author: bademi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-14 20:39:58

Rastreé 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 apagados para la vista principal, esa vista no podía cambiar de tamaño y, por lo tanto, se desplazó hacia abajo en su totalidad cuando apareció la barra de llamada.

Desactivar las características simuladas, luego cambiar el tamaño de la vista y configurar los resortes correctamente causó que la animación se produjera y mi método se called.

Un problema adicional en la depuración es que el simulador sale de la aplicación cuando el estado de la llamada está activado a través del menú. Salir de app = sin depurador.

 6
Author: Steve Weller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-09 14:41:40

¿Has mirado la disposición necesaria?

El fragmento de documentación se encuentra a continuación. ¿Funciona la animación si llamas a este método explícitamente durante la animación?

Layout necesario Establece las subviews si es necesario.

- (void)layoutIfNeeded

Discusión Utilice este método para forzar el diseño de subviews antes de dibujar.

Disponibilidad Disponible en iPhone OS 2.0 y versiones posteriores.

 3
Author: Willi Ballenthin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-08 04:12:24

Al migrar una aplicación OpenGL desde SDK 3 a 4, layoutSubviews ya no se llamaba. Después de mucho ensayo y error, finalmente abrí MainWindow.xib, seleccionó el objeto Window, en el inspector eligió la pestaña Window Attributes (leftmost) y marcó "Visible at launch". Parece que en SDK 3 todavía se utiliza para causar una llamada layoutSubviews, pero no en 4.

6 horas de frustración acabadas.

 2
Author: Tal Yaniv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-24 07:13:42

Otra parte del rompecabezas es que la ventana debe hacerse clave:

[window makeKeyAndVisible];

De lo contrario, las subviews no se redimensionan automáticamente.

 0
Author: Steve Weller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-30 06:08:57

Un caso bastante oscuro, pero potencialmente importante cuando layoutSubviews nunca se llama es:

import UIKit

class View: UIView {

    override class var layerClass: AnyClass { return Layer.self }

    class Layer: CALayer {
        override func layoutSublayers() {
            // if we don't call super.layoutSublayers()...
            print(type(of: self), #function)
        }
    }

    override func layoutSubviews() {
        // ... this method never gets called by the OS!
        print(type(of: self), #function)
    }
}

let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
 0
Author: milos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-02 14:48:08