2012-09-21 8 views
55

Estoy desarrollando con el diseño automático iOS 6iOS AutoLayout: obtenga el ancho del marco

Me gustaría registrar un mensaje que muestre el ancho del marco de la vista.

Puedo ver el textView en la pantalla.

Pero obtengo el ancho y la altura como cero, ¿me falta algo?

NSLog(@"textView = %p", self.textView); 
NSLog(@"height  = %f", self.textView.frame.size.height); 
NSLog(@"width  = %f", self.textView.frame.size.width); 

textView = 0x882de00 
height  = 0.000000 
width  = 0.000000 

Respuesta

56

Creo que el diseño automático no ha tenido el tiempo para dar formato a sus vistas en el momento de llamar a esto. El diseño automático no se ha producido cuando se llama a viewDidLoad, porque se llama justo después de que se cargan las vistas y solo después de eso las vistas se colocan en la jerarquía de vistas del controlador de vista y finalmente se distribuyen (en el método layoutSubviews de la vista).

Editar: esta respuesta señala por qué el escenario en la pregunta no funciona. @dreamzor's answer indica dónde colocar su código para resolverlo.

+0

Intenté registrar el mensaje en 'viewDidLoad'. Qué método se invoca después de que se haya completado el diseño automático. La razón por la que pregunto es porque quiero calcular el ancho antes de que el usuario pueda interactuar con textView. Por lo tanto, registrar la descripción del objeto puede no ser útil porque quiero usar el ancho para otro cálculo. – user1046037

+1

No, 'viewDidLoad' sucede antes del diseño automático.El diseño automático se realiza de forma perezosa después de que se haya agregado una vista a otra vista (que es poco después de que se haya llamado a 'viewWillAppear', pero probablemente no de manera confiable antes de' viewDidAppear'). La única forma confiable de saber es cuándo termina 'layoutSubviews' en la vista del controlador de vista. – Jesper

+1

¿Por qué estás tratando de obtener el marco de todos modos? Si desea hacer cálculos basados ​​en él y hacer el diseño usted mismo, probablemente terminará luchando contra el diseño automático. – Jesper

28

Solución

  • lugar que el código en viewDidAppear

Razón

  • viewDidLoad ocurre antes de completar el diseño automático. Por lo tanto, la posición aún no establecida por el diseño automático que se especificó en xib
  • viewDidAppear ocurre una vez que se completa el diseño automático.
+1

Coloqué el código en viewDidAppear y aún así, el marco de mi vista NSLog muestra ceros. – dreamzor

+0

En realidad, se llama a viewDidAppear antes de viewDidLayoutSubviews que a iOS 6.0, por lo que dreamzor tiene razón. – vedrano

+4

En iOS 6, en función de mis pruebas, utilicé el controlador de navegación en el segundo controlador, se llamó a 'viewDidLayoutSubviews' antes de' viewDidAppear' pero en 'viewDidLayoutSubviews' el ancho del fotograma de la subvista sigue siendo cero. Solo en 'viewDidAppear', el ancho del cuadro de la subvista parece tener el valor correcto. – user1046037

147

En realidad, las respuestas anteriores no son correctas. Los seguí y obtuve ceros una y otra vez.

El truco es colocar su código marco dependiente al método viewDidLayoutSubviews, que

notifica al controlador de vista de que su punto de vista simplemente expuso sus subvistas.

No olvide que este método se llama varias veces y no forma parte del ciclo de vida de ViewController, así que tenga cuidado al usarlo.

Espero que sea útil para alguien.

Solo quería agregar, que para mi programa sin modo horizontal NO usar Diseño automático es mucho más simple ...He intentado, aunque = D

+9

Por experiencia, esta es la devolución de llamada más temprana después de que Autolayout funciona. Recomiendo usar, por ejemplo, un BOOL para captar la primera vez que se llama y hacer una lógica dependiente del cuadro. No es muy elegante, pero hace el trabajo hasta que haya una devolución de llamada adecuada para las restricciones de autodiseño específicas. – ArkReversed

+3

@dreamzor, ¿cómo puedo saber si es el último viewDidLayoutSubviews? Encontré en iOS 7, solo se llamará a viewDidLayoutSubviews antes de viewDidAppear, pero en iOS 8, veo un total de viewDidLayoutSubviews antes de viewDidAppear. Esto es molesto, porque el primer viewDidLayoutSubviews dará un tamaño de fotograma incorrecto en iOS 8, así que tengo que ignorarlo por primera vez – Wingzero

+0

@Wingzero En mi proyecto, la quinta vez es correcta, entonces ¿cómo puedo ignorar otros? –

13

En realidad logré vigor la actualización de diseño antes de mi código dentro del viewDidLoad:

override func viewDidLoad() { 
     super.viewDidLoad() 

     println("bounds before \(self.previewContainer.bounds)"); 
     //on iPhone 6 plus -> prints bounds before (0.0,0.0,320.0,320.0) 

     self.view.setNeedsLayout() 
     self.view.layoutIfNeeded() 

     println("bounds after \(self.previewContainer.bounds)"); 
     //on iPhone 6 plus -> prints bounds after (0.0,0.0,414.0,414.0) 

     //Size dependent code works here 
     self.create() 
    } 

ACTUALIZACIÓN: Esto no parece que trabajar más

25

Incluir en su viewDidLoad()

self.view.setNeedsLayout() 
self.view.layoutIfNeeded() 

Antes de acceder a suv iew.frame.size.width

2

iOS diseño automático - obtener el tamaño del marco ancho

-(void) layoutSubviews{ 
     [self layoutIfNeeded]; 
     //right you code to set frame its will work to get frame and set frame. 
     CALayer *bottomBorder = [CALayer layer]; 
     bottomBorder.frame = CGRectMake(0.0f, bkView.frame.size.height - 1, bkView.frame.size.width, 1.0f); 
     bottomBorder.backgroundColor = [UIColor blackColor].CGColor; 
     [bkView.layer addSublayer:bottomBorder]; 
    } 
5

Ninguna de las respuestas anteriores trabajado por completo para mí, excepto viewDidLoad pero que no tiene el efecto secundario de no mostrar lo que quiero hasta después de que la vista se haya animado, lo cual parece pobre.

viewDidLayoutSubviews debería ser el lugar correcto para ejecutar código que se basa en el diseño automático de ser completa, pero, como otros han señalado que se llama varias veces en los últimos versiones de iOS y no se puede saber cuál es la última llamada.

Así que resolví esto con un pequeño truco. En mi guión gráfico, mySubview debería ser más pequeño que el que contiene self.view. Pero cuando se llama por primera vez a viewDidLayoutSubviews, mySubview todavía tiene un ancho de 600, mientras que self.view parece estar configurado correctamente (este es un proyecto de iPhone). Entonces, todo lo que tengo que hacer es monitorear las llamadas subsiguientes y verificar los anchos relativos. Una vez que mySubview es menor que self.view, puedo estar seguro de que se ha distribuido correctamente.

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    if self.mySubview.bounds.size.width < self.view.bounds.size.width { 

     // mySubview's width became less than the view's width, so it is 
     // safe to assume it is now laid out correctly... 

    } 
} 

Esto tiene la ventaja de no depender de los números codificados de forma rígida, por lo que puede trabajar en todos los formatos de iPhone, por ejemplo. Por supuesto, puede no ser una panacea en todos los casos o en todos los dispositivos, pero probablemente haya muchas maneras ingeniosas de hacer comprobaciones similares de tamaños relativos.

Y no, no deberíamos tener que hacer esto, pero hasta que Apple nos proporcione algunas devoluciones de llamada más confiables, estamos todos atrapados con eso.

7

Esta es una característica realmente extraña. Pero he encontrado:

Si desea obtener bastidor sin el uso de layoutsubviews método, utilice la siguiente:

dispatch_async(dispatch_get_main_queue(), ^{ 
     NSLog(@"View frame: %@", NSStringFromCGRect(view.frame)); 
    }); 

Esto es realmente extraño !!!

+0

muchas gracias sam – Subramani

0

Solo puede averiguar el tamaño después del primer pase de disposición. O simplemente llame al método siguiente luego de obtener el ancho real de su vista.

[yourView layoutIfNeeded]; 
Cuestiones relacionadas