2012-09-21 9 views
55

Sto sviluppando utilizzando il layout automatico di iOS 6AutoLayout di iOS - ottieni la dimensione della cornice larghezza

Vorrei registrare un messaggio che mostri la larghezza del frame della vista.

Posso vedere il testoView sullo schermo.

Ma ottengo la larghezza e l'altezza come zero, mi manca qualcosa?

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 

risposta

56

Penso che il layout automatico non abbia avuto il tempo di impaginare le visualizzazioni nel momento in cui viene chiamato. Il layout automatico non si è verificato per il momento in cui viene chiamato il numero viewDidLoad, perché viene chiamato subito dopo il caricamento delle viste e solo dopo che le viste vengono posizionate nella gerarchia di visualizzazione del controller della vista e infine disposte (nel metodo layoutSubviews della vista).

Modifica: questa risposta indica perché lo scenario nella domanda non funziona. @dreamzor's answer indica dove posizionare il codice per risolverlo.

+0

Ho provato a registrare il messaggio in 'viewDidLoad'. Quale metodo viene richiamato dopo che il layout automatico è stato completato. Il motivo per cui lo chiedo è perché voglio calcolare la larghezza prima che l'utente possa interagire con textView. Quindi la registrazione della descrizione dell'oggetto potrebbe non aiutare bcuz Voglio usare la larghezza per qualche altro calcolo. – user1046037

+1

No, 'viewDidLoad' si verifica prima del layout automatico.Il layout automatico avviene pigramente dopo che una vista è stata aggiunta ad un'altra vista (che è stata chiamata poco dopo 'viewWillAppear', ma probabilmente non attendibilmente prima di' viewDidAppear'). L'unico modo affidabile per sapere è quando 'layoutSubviews' è finito sulla vista del controller della vista. – Jesper

+1

Perché stai cercando di ottenere il frame comunque? Se vuoi fare calcoli basati su di esso e fare il layout te stesso, probabilmente finirai per combattere il layout automatico. – Jesper

28

Soluzione

  • Inserire il codice nella viewDidAppear

Motivo

  • viewDidLoad avviene prima autolayout è completata. Quindi la posizione non è ancora impostata dall'output automatico specificato in xib
  • viewDidAppear accade dopo che l'autolayout è completato.
+1

Ho inserito il codice in viewDidAppear e tuttavia ancora, il frame della mia vista NSLog mostra gli zeri. – dreamzor

+0

In realtà viewDidAppear viene chiamato prima di viewDidLayoutSubviews come per iOS 6.0, quindi dreamzor ha ragione. – vedrano

+4

In iOS 6, in base ai miei test, ho utilizzato il controller di navigazione nel secondo controller, il 'viewDidLayoutSubviews' è stato chiamato prima di' viewDidAppear', ma in 'viewDidLayoutSubviews' la larghezza del riquadro della sottoview rimane zero. Solo in 'viewDidAppear', la larghezza del frame della subview sembra avere il valore corretto. – user1046037

147

In realtà, le risposte precedenti non sono corrette. Li ho seguiti e ottenuto zeri ancora e ancora.

Il trucco è quello di inserire il codice telaio-dipendente al metodo viewDidLayoutSubviews, che

notifica al controller della vista che la sua vista appena posato le sue subviews.

Non dimenticare che questo metodo viene chiamato più volte e non fa parte del ciclo di vita di ViewController, quindi fai attenzione mentre lo usi.

Spero che possa essere utile a qualcuno.

Volevo solo aggiungere che per il mio programma senza modalità orizzontale NON si utilizza Auto Layout è molto più semplice ...Ci ho provato, anche se D =

+9

Per esperienza, questa è la prima richiamata dopo l'esecuzione del caricamento automatico. Raccomando, ad esempio, di utilizzare BOOL per catturare la prima volta che viene chiamato e fare una logica dipendente dal frame. Non è molto elegante ma svolge il lavoro fino a quando non ci sono callback appropriati per specifici vincoli di autolayout. – ArkReversed

+3

@dreamzor, come faccio a sapere se è l'ultima viewDidLayoutSubviews? Ho trovato su iOS 7, solo una viewDidLayoutSubviews sarà chiamata prima di viewDidAppear, ma su iOS 8, vedo mutiple viewDidLayoutSubviews prima di viewDidAppear. Questo è fastidioso, perché la prima viewDidLayoutSubviews darà una dimensione del frame errata su iOS 8, quindi devo ignorarlo per la prima volta – Wingzero

+0

@Wingzero Nel mio progetto la quinta volta è corretta, quindi come posso ignorare gli altri? –

13

In realtà sono riuscito a forza l'aggiornamento layout prima il mio codice all'interno 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() 
    } 

UPDATE: Questo non sembra funzionare più

25

Includi nel tuo viewDidLoad()

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

Prima di accedere a yourv iew.frame.size.width

2

iOS AutoLayout - ottenere dimensioni del fotogramma larghezza

-(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

Nessuna delle risposte di cui sopra ha lavorato completamente a me, se non viewDidLoad ma che ha l'effetto collaterale di non mostrare quello che voglio fino a dopo che la vista si è animata, il che sembra scadente.

viewDidLayoutSubviewsdovrebbe essere il posto giusto per eseguire il codice che si basa sul layout automatico essere completo, ma come altri hanno fatto notare è chiamato più volte nelle versioni iOS recenti e non si può sapere quale è l'ultima chiamata.

Così ho risolto questo con un piccolo hack. Nel mio storyboard, mySubview dovrebbe essere più piccolo del suo contenente self.view. Ma quando viene chiamato per la prima volta viewDidLayoutSubviews, mySubview ha ancora una larghezza di 600, mentre self.view sembra essere impostato correttamente (questo è un progetto per iPhone). Quindi tutto ciò che devo fare è monitorare le chiamate successive e controllare le larghezze relative. Una volta che mySubview è inferiore a self.view, posso essere sicuro che sia stato impostato correttamente.

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

    } 
} 

Questo ha il vantaggio di non fare affidamento su numeri hard-coded, in modo che possa funzionare su tutti i fattori di forma di iPhone, per esempio. Ovviamente potrebbe non essere una panacea in tutti i casi o su tutti i dispositivi, ma ci sono probabilmente molti modi ingegnosi per eseguire controlli simili delle dimensioni relative.

E no, non dovremmo doverlo fare, ma finché Apple non ci darà alcuni callback più affidabili, siamo tutti bloccati.

7

Questa è una caratteristica davvero strana. Ma ho trovato:

Se si desidera ottenere telaio senza usare layoutSubviews metodo, utilizzare questo:

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

Questo è davvero strano !!!

+0

grazie mille sam – Subramani

0

È possibile scoprire la dimensione solo dopo il primo passaggio di layout. Oppure chiama semplicemente il metodo seguente, dopo aver ottenuto la larghezza effettiva della tua vista.

[yourView layoutIfNeeded]; 
Problemi correlati