2015-07-10 8 views
10

Ho appena visto in Facebook SDK per iOS, chiamano [super layoutSubviews]; alla fine e non all'inizio del metodo layoutSubviews. Per quanto ne so, dovremmo sempre farlo come prima linea. In questo modo, può creare un comportamento imprevisto per l'interfaccia utente?Qual è il modo corretto per chiamare [super layoutsubviews]?

- (void)layoutSubviews 
{ 
    CGSize size = self.bounds.size; 
    CGSize longTitleSize = [self sizeThatFits:size title:[self _longLogInTitle]]; 
    NSString *title = (longTitleSize.width <= size.width ? 
        [self _longLogInTitle] : 
        [self _shortLogInTitle]); 
    if (![title isEqualToString:[self titleForState:UIControlStateNormal]]) { 
    [self setTitle:title forState:UIControlStateNormal]; 
    } 

    [super layoutSubviews]; 
} 
+0

"Per quanto ne so, dovremmo sempre farlo come prima linea" Come fai a "sapere" quello? – matt

+1

@matt, credo che questa sia la convenzione utilizzata dalla comunità degli sviluppatori iOS poiché la super-classe potrebbe avere alcune impostazioni di default/generali che potrebbero influire sul nostro layout personalizzato da non applicare (se lo facciamo alla fine del metodo). Analogamente a chiamare super in costruttori/inizializzatori come prima riga. – ppalancica

+1

"la super classe potrebbe avere alcune impostazioni di default/generali che potrebbero influenzare il nostro layout personalizzato da non applicare (se lo facciamo alla fine del metodo)." Sì, è assolutamente vero. Ma non è lo stesso di "dovrebbe sempre". – matt

risposta

7

Secondo il UIView Class Reference,

L'implementazione predefinita di questo metodo non fa nulla su iOS 5.1 e versioni precedenti. In caso contrario, l'implementazione predefinita utilizza qualsiasi vincolo impostato per determinare la dimensione e la posizione di qualsiasi subview.

Così, che l'esempio applicazione Facebook SDK chiama [super layoutSubviews] al termine della loro applicazione potrebbe essere un artefatto dell'essere app inizialmente costruito per una versione IOS prima IOS 5.1.

Per le versioni più recenti di iOS, è necessario chiamare [super layoutSubviews] all'inizio dell'implementazione. Altrimenti, la superclasse riorganizzerà le sottoview dopo aver eseguito il layout personalizzato, ignorando in modo efficace l'implementazione di 'layoutSubviews()'.

2

È sempre necessario chiamare [super layoutSubviews] per ultima, se la dimensione del contenuto intrinseco di una vista verrà modificata. Se si modifica il titolo del pulsante, verrà modificata la dimensione intrinseca del contenuto di UIButton, quindi l'ultima chiamata.

La prima chiamata a [super layoutSubviews] è sempre necessaria perché iOS aggiorna il layout in base ai vincoli. Tuttavia, il modo tecnico più corretto di attuare il vostro campione dovrebbe essere:

- (void)layoutSubviews 
{ 
[super layoutSubviews]; 
    CGSize size = self.bounds.size; 
    CGSize longTitleSize = [self sizeThatFits:size title:[self _longLogInTitle]]; 
    NSString *title = (longTitleSize.width <= size.width ? 
        [self _longLogInTitle] : 
        [self _shortLogInTitle]); 
    if (![title isEqualToString:[self titleForState:UIControlStateNormal]]) { 
    [self setTitle:title forState:UIControlStateNormal]; 
    } 

    [super layoutSubviews]; 
} 
+0

Solo curioso: la tua affermazione sulle dimensioni del contenuto intrinseco è supportata nella documentazione ovunque? – ndmeiri

+0

Purtroppo no, ma se ci pensate: la dimensione intrinseca del contenuto può essere aggiornata solo con setNeedsLayout, che chiama direttamente layoutSubviews. Se modifichi la dimensione del contenuto intrinseco (cambia titolo pulsante) in layoutSubviews il contenitore (Button) non può applicare correttamente queste modifiche se [super layoutSubviews] non verrà chiamato in seguito. – seeya

+0

@ndmeiri Quando si esegue contro iOS7, ho visto errori di runtime se ho chiamato solo [super layoutSubviews]: terminando l'app a causa dell'eccezione non rilevata 'NSInternalInconsistencyException', motivo: 'Layout automatico ancora richiesto dopo l'esecuzione -layoutSubviews. L'implementazione di {View} di -layoutSubviews deve essere superata. ' – Matthew

4

sguardo nel codice, prima di [layoutSubviews eccellenti], non si tratta di telaio. quindi metterlo alla fine potrebbe funzionare anche bene. Immagino che il programmatore debba voler controllare il titolo e modificare il titolo in base ad alcune regole, pensa che ogni volta che viene chiamato il layout di videate è un'occasione giusta per farlo, quindi inserisce il codice qui.