2013-05-28 14 views
7

Tutti sanno che non ci si può fidare della dimensione del frame su un metodo init/viewDidLoad di UIViewController; questo:UIViewController viewDidLoad errato larghezza/altezza

- (void)viewDidLoad: { 
    NSLog(@"%d", self.view.frame.size.width); 
} 

stamperà taglie sbagliate in molte occasioni (in particolare è praticamente rotto in modalità orizzontale)

Questo effettivamente restituire risultati sempre corretti quindi è bene per il layout dei subviews:

- (void)viewWillAppear: { 
    NSLog(@"%d", self.view.frame.size.width); 
} 

Il problema è che viewWillAppears viene chiamato ogni volta che viene visualizzata la vista, quindi non è adatto per allocare o aggiungere sottoview. Quindi finisci per dichiarare ogni singola vista nell'interfaccia e ti ritroverai con enormi file di intestazione che non mi piacciono affatto poiché la maggior parte degli elementi non richiede ulteriori manipolazioni dopo l'installazione iniziale.

Quindi, la prima domanda è: C'è un modo migliore per gestire il posizionamento delle sottoview?

La seconda domanda è molto correlata, diciamo che ho una sottoclasse di UIView che include vari altri sottoview. Lo dichiaro all'interno della mia interfaccia e lo alloco/inizialo nel mio metodo init/viewDidLoad.

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    ... 
    menu = [[SNKSlidingMenu alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); 
    ... 
} 

Come già sappiamo ora abbiamo bisogno di riposizionarla in viewWillAppear per ottenere una lettura più accurata

- (void)viewWillAppear:(BOOL)animated{ 
    .... 
    menu.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); 
    .... 
} 

Il problema è che, naturalmente, ha bisogno di essere riposizionato come bene tutto il subviews. Questo viene fatto dalla funzione layoutSubviews che viene chiamata automaticamente, ma abbiamo lo stesso problema: Tutte le sottoview devono essere dichiarate all'interno dell'interfaccia della classe SNKSlidingMenu. C'è un modo per aggirare questo?

Grazie.

+1

utilizzare l'autolayout o impostare le maschere di autoresizing? – jrturton

risposta

7

Se ci si rivolge iOS 5.0 o successivo è possibile utilizzare viewWillLayoutSubviews e viewDidLayoutSubviews per apportare modifiche.

Per quanto riguarda la seconda domanda, se è necessario accedere a una variabile di istanza in un altro metodo diverso da init, è necessario tenerlo in giro, non vedo alcun problema.

Tuttavia, è possibile provare a utilizzare i layout automatici e impostare le regole tra le visualizzazioni secondarie in modo che siano disposte automaticamente per te senza la necessità di mantenere un riferimento.

+0

d'accordo, ma poi è piuttosto stupido dover usare initWithFrame per inizializzare ogni singola vista. Mi sembra un sacco di codice duplicato e sembra che ti costringa a utilizzare molte variabili di istanza. I layout automatici sono solo per iOS più recenti. – ksn

+0

Il vecchio 'autoresizingMask' potrebbe essere sufficiente anche per te. Per quanto riguarda il codice duplicato: se si duplica un sacco di quel codice, è possibile creare sottoclassi 'UIView' personalizzate in modo da non duplicare o avere metodi di supporto che creano le viste per voi. Se pubblichi più codice potremmo essere in grado di aiutarti di più. – pgb

6

viewDidLoad ottiene solo chiamato quando il vostro punto di vista è creato, ma un sacco di cose può influenzare dimensioni s' il frame, e che non venga ancora una volta chiamato quando frame modifiche.

Invece:

  • creare subviews in viewDidLoad
  • impostare le loro dimensioni in viewWillLayoutSubviews.

vedere qualche discussione supplementare qui per la movimentazione di rotazione: https://stackoverflow.com/a/16421170/1445366

2

viewWillLayoutSubviews e viewDidLayoutSubviews possono risolvere questo problema.
Ma i due methed sarebbero stati eseguiti più volte. questo è il mio codice per ottenere corretto self.view.frame.

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    ... 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    // init you view and set it`s frame. this can get correct frame. 
    ... 
    } 
    ... 
} 
+0

Questa è l'unica soluzione che ha funzionato per me. Anche se, è un pò brutta alcuni vista iniziale strano apre una frazione di secondo prima che i calci dispatch_async in Per Swift4:. \t \t DispatchQueue.main.async { \t \t} –

Problemi correlati