2012-02-28 11 views
11

Estoy tratando de ejecutar código siguiente en el método viewDidLoad de mi proyecto controlador de vista individual:no se puede actualizar view.layer.frame en viewDidLoad?

self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 

Pero no da la inserción deseada. Sin embargo, otros cambios de interfaz de usuario que hago en el mismo método funcionan por ejemplo

self.view.layer.backgroundColor = [UIColor orangeColor].CGColor; 

Por encima de línea de código de trabajo y el fondo es el cambio de color naranja pero el marco no es así.

El recuadro funciona solo si coloco la línea de código en viewDidAppear. Me gustaría entender la razón clave de este comportamiento si alguien puede explicarlo. Gracias de antemano.

Respuesta

11

El método viewDidLoad es demasiado temprano para establecer el marco de su vista porque algo más está cambiando el marco más tarde.

Por ejemplo, si este es su controlador de vista raíz, el objeto UIWindow establecerá el marco de la vista cuando se agregue la vista a sí mismo como una subvista. El método viewDidLoad se ejecuta tan pronto como loadView regresa, antes de que cualquier objeto externo (como el UIWindow) pueda poner sus manos en la vista.

Puede probar esto mediante el uso de una vista personalizada (si no está ya) y primordial setFrame: en la clase de vista personalizada:

- (void)setFrame:(CGRect)frame { 
    [super setFrame:frame]; 
} 

Deja un punto de interrupción en ese método y verá que la el marco de view se establece algún tiempo después de que viewDidLoad regresa.

+0

nota, también se pueden observar los cambios de valor mediante el uso de [Valor Llave Observando] (http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html), aunque no dará exactamente el mismo resultado que la creación de subclases (diferente cuando se usan puntos de interrupción) –

+0

@lindonfox No se puede observar confiablemente el 'fotograma 'de una vista con KVO. También debe observar su 'center',' bounds' y 'transform'. –

+0

¿Qué tal 'viewWillAppear'? Me parece que hacerlo en 'viewDidAppear' es demasiado tarde y dará lugar a glitches visuales. – devios1

5

La respuesta de Rob Mayoff es correcta y excelente, pero por decirlo ligeramente: viewDidLoad solo significa que la vista se ha cargado, es decir, que el controlador de vista ha obtenido su vista. No significa que la vista se haya colocado en la interfaz. Eso, de hecho, es una de las cosas que viewDidAppear: significa, y es por eso que funcionó cuando ejecutó su código allí.

El truco en este tipo de situación, en el que desea inicializar algo sobre la vista, es hacerlo lo suficientemente tarde pero hacerlo solo una vez. viewDidAppear: podría volver a llamar fácilmente más tarde, pero no desea volver a inicializar la vista (a menos que se haya descargado). En iOS 5, isMovingToParentViewController le permite distinguir las circunstancias particulares que está buscando. Antes de eso, podría ser necesario configurar un indicador BOOL para que realice inicializaciones finales solo una vez.

Una trampa relacionada es lo que sucede cuando la aplicación se inicia en orientación horizontal. Aquí, también, viewDidLoad es demasiado pronto porque la interfaz aún no ha girado en el paisaje.

Sin embargo, este problema no debería surgir en absoluto. No debe ser de su incumbencia insertar una vista de controlador de vista. La vista es el controlador de vista raíz, en cuyo caso su tamaño se atiende automáticamente o es el elemento secundario de un controlador de vista principal, en cuyo caso es el trabajo del controlador de vista principal el tamaño de la vista (como UINavigationController, por ejemplo, ya lo hace), o la vista debe presentarse de forma modal, en cuyo caso su tamaño se establecerá automáticamente para que coincida con la vista a la que reemplaza. Por lo tanto, sugeriría que la pregunta misma sugiera que está haciendo algo mal.

2

Crea tu proyecto con una versión anterior de Xcode (por ejemplo, estoy usando Xcode 4.3.3 para esto). Entonces puede usar el método setFrame: con viewDidLoad en cualquier versión de Xcode.

0

También experimenté este problema en el tutorial de Ray Wenderlich 'Introducción a CALayers'. http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial

Parece que reducir la vista de toda la vista de los controladores no es lo mejor que se puede hacer. En lugar de crear una vista sub y llame CGRectInset en la que por ejemplo, en los controladores de vista viewDidLoad

UIView *viewToManipulate = [[UIView alloc] initWithFrame:CGRectMake(0.0,0.0, self.view.bounds.size.width, self.view.bounds.size.height)]; 

[self.view addSubview:viewToManipulate]; 

viewToManipulate.backgroundColor = [UIColor redColor]; 
viewToManipulate.layer.cornerRadius = 20.0; 
viewToManipulate.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 
+0

¿Puede ampliar por qué reducir la vista de todo el controlador de vista no es bueno? –

+0

Tuve el mismo problema con el tutorial de Ray Wenderlich 'Introducción a los CALayers'. La solución (al utilizar XCode 4.6) era cambiar el código a la función "viewDidAppear". No viewWillAppear o viewDidLoad, pero viewDidAppear. ¡Y luego funcionará! Me pregunto si el nuevo y horrible "uso de la función de auto-uso" de XCode 4.6 está impidiendo que el código original funcione ...? –

17

Creo que el problema está ejecutando en esta línea:

self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 

se puede explicar así:

  • en viewDidLoad, las propiedades están establecidas, pero el marco de las vistas aún no está definido.
  • en el momento en que se activa viewWillAppear, se establecerán. Eso explica por qué esa línea de código funciona allí.
  • Pero desde iOS 5, hay otro método llamado después de viewDidLoad y antes de viewWillAppear en el que se establecen los marcos de vista: viewDidLayoutSubviews.

Puede encontrar la explicación completa de esto en el curso Stanford CS193P de esta temporada sobre la programación de iOS (muy bueno por cierto).

Así que si quieres que funcione una sola vez, utilice:

- (void)viewDidLayoutSubviews 
{ 
    self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 
} 

PS: He publicado esta respuesta en el foro de Ray también. Saludos, Fred

Cuestiones relacionadas