2012-03-02 18 views
36

Quando avvio il ViewController nella modalità landscape (dopo aver chiamato viewDidLoad), stampo il fotogramma che invece mi dà le dimensioni del fotogramma per la modalità verticale.UIViewController restituisce frame non valido?

È un bug qualche suggerimento?

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    NSLog(@"%@", NSStringFromCGRect(self.view.frame)); 
    // Result is (0, 0 , 768, 1024) 
} 
+1

E per quanto riguarda viewDidAppear? – Luke

+1

viewDidAppear ha funzionato bene – aryaxt

risposta

157

Ci sono un paio di cose che non capisci.

In primo luogo, il sistema invia viewDidLoad subito dopo aver caricato il pennino. Non ha ancora aggiunto la vista alla gerarchia della vista. Quindi non ha ridimensionato la tua vista in base alla rotazione del dispositivo.

In secondo luogo, la cornice di una vista si trova nello spazio delle coordinate della superview. Se questa è la tua vista root, la sua superview sarà il UIWindow (una volta che il sistema aggiunge effettivamente la tua vista alla gerarchia della vista). Lo UIWindow gestisce la rotazione impostando la trasformazione della sua sottoview. Ciò significa che la cornice della vista non sarà necessariamente quella che ti aspetti.

Ecco la gerarchia vista in orientamento verticale:

(lldb) po [[UIApp keyWindow] recursiveDescription] 
(id) $1 = 0x09532dc0 <UIWindow: 0x9632900; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x96329f0>> 
    | <UIView: 0x9634ee0; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0x9633b50>> 

ed ecco la gerarchia vista nel paesaggio-sinistra orientamento:

(lldb) po [[UIApp keyWindow] recursiveDescription] 
(id) $2 = 0x09635e70 <UIWindow: 0x9632900; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x96329f0>> 
    | <UIView: 0x9634ee0; frame = (20 0; 748 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x9633b50>> 

Si noti che con orientamento orizzontale, la dimensione del telaio è 748 x 1024 , non 1024 x 748.

Quello che probabilmente si vuole vedere, se questa è la vista radice, è la vista b ounds:

(lldb) p (CGRect)[0x9634ee0 bounds] 
(CGRect) $3 = { 
    (CGPoint) origin = { 
    (CGFloat) x = 0 
    (CGFloat) y = 0 
    } 
    (CGSize) size = { 
    (CGFloat) width = 1024 
    (CGFloat) height = 748 
    } 
} 

Presumibilmente si vogliono sapere quando la vista della trasformazione, il telaio e limiti vengono aggiornati. Se l'interfaccia è in un orientamento orizzontale quando il controller della vista carica la sua vista, si ricevono messaggi in questo ordine:

{{0, 0}, {768, 1004}} viewDidLoad 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} viewWillAppear: 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} willRotateToInterfaceOrientation:duration: 
{{0, 0}, {1024, 748}} viewWillLayoutSubviews 
{{0, 0}, {1024, 748}} layoutSubviews 
{{0, 0}, {1024, 748}} viewDidLayoutSubviews 
{{0, 0}, {1024, 748}} willAnimateRotationToInterfaceOrientation:duration: 
{{0, 0}, {1024, 748}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {1024, 748}} viewDidAppear: 

Si può vedere che i limiti della vostra vista cambiano dopo si riceve willRotateToInterfaceOrientation:duration: e prima voi ricevere viewWillLayoutSubviews.

I metodi viewWillLayoutSubviews e viewDidLayoutSubviews sono nuovi per iOS 5.0.

Il messaggio layoutSubviews viene inviato alla vista, non al controller della vista, quindi sarà necessario creare una sottoclasse personalizzata UIView se si desidera utilizzarla.

+0

Grazie grandi informazioni – aryaxt

+1

Questa è una grande spiegazione. – schellsan

+1

Una delle migliori spiegazioni che ho sentito. Grazie – Jon

2

Ecco una soluzione pulita.

Ho riscontrato lo stesso problema e insisto per utilizzare frame in tutta la mia app. Non voglio fare un'eccezione per il controller della vista radice. Ho notato che il frame del controller della visualizzazione radice visualizzava le dimensioni del ritratto, ma tutte le sottoview avevano le dimensioni del paesaggio corrette.

Poiché è solo il controller della vista radice che si comporta in modo diverso, possiamo impostare un controller di visualizzazione vuoto standard come controller della vista radice e aggiungere il nostro controller di visualizzazione personalizzato. (Codice sotto.)

È quindi possibile utilizzare frame come si desidera, nel proprio controller di visualizzazione personalizzato.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    // Override point for customization after application launch. 

    self.window.rootViewController = [[UIViewController alloc] init]; 

    [self.window makeKeyAndVisible]; 

    self.viewController = [[ViewController alloc] initWithNibName:nil bundle:nil]; 
    [self.window.rootViewController addChildViewController:self.viewController]; 
    [self.window.rootViewController.view addSubview:self.viewController.view]; 

    return YES; 
} 
Problemi correlati