2011-10-11 15 views
151

Ho una vista personalizzata che disegna una bitmap scorrevole sullo schermo. Per inizializzarlo, ho bisogno di passare la dimensione in pixel dell'oggetto di layout principale. Ma durante le funzioni onCreate e onResume, il Layout non è ancora stato disegnato, quindi layout.getMeasuredHeight() restituisce 0.Come puoi sapere quando è stato disegnato un layout?

Come soluzione alternativa, ho aggiunto un gestore per attendere un secondo e quindi misurare. Funziona, ma è sciatto, e non ho idea di quanto posso tagliare il tempo prima che finisca prima che il layout venga disegnato.

Quello che voglio sapere è, come posso rilevare quando viene tracciato un layout? C'è un evento o un callback?

risposta

316

È possibile aggiungere un albero osservatore al layout. Questo dovrebbe restituire la larghezza e l'altezza corrette. onCreate() viene chiamato prima che venga eseguito il layout delle viste secondarie. Quindi la larghezza e l'altezza non sono ancora calcolate. Per ottenere l'altezza e la larghezza, mettere questo sul metodo onCreate():

final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID); 
ViewTreeObserver vto = layout.getViewTreeObserver(); 
vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() { 
    @Override 
    public void onGlobalLayout() { 
     layout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
     int width = layout.getMeasuredWidth(); 
     int height = layout.getMeasuredHeight(); 

    } 
}); 
+1

Questo ha funzionato. Grazie! ViewTreeObserver è esattamente la cosa che volevo. –

+0

Grazie mille! Esattamente l'esempio che stavo cercando, inclusa la rimozione immediata dell'ascoltatore al primo trigger. – baske

+0

Sì, questo è quello che ha detto di fare Romain Guy! –

1

Quando onMeasure è chiamato vista prende il misurata larghezza/altezza. Dopo questo, puoi chiamare layout.getMeasuredHeight().

+3

Non dovresti creare la tua vista personalizzata per sapere quando incendi OnMeasure? –

+0

Sì, è necessario utilizzare le visualizzazioni personalizzate per accedere su misura. –

2

Un'altra risposta è:
Prova a verificare le dimensioni di visualizzazione a onWindowFocusChanged.

18

Per evitare il codice deprecato e le avvertenze si può usare:

view.getViewTreeObserver().addOnGlobalLayoutListener(
     new ViewTreeObserver.OnGlobalLayoutListener() { 
      @SuppressWarnings("deprecation") 
      @Override 
      public void onGlobalLayout() { 
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
        view.getViewTreeObserver() 
          .removeOnGlobalLayoutListener(this); 
       } else { 
        view.getViewTreeObserver() 
          .removeGlobalOnLayoutListener(this); 
       } 
       yourFunctionHere(); 
      } 
     }); 
+1

Per utilizzare questo codice, "vista" deve essere dichiarato come "finale". – BeccaP

+2

utilizzare questa condizione invece Build.VERSION.SDK_INT HendraWD

35

Un modo molto semplice è quello di chiamare semplicemente post() sul layout. Questo eseguirà il tuo codice il prossimo passo, dopo che la tua vista è già stata creata.

YOUR_LAYOUT.post(new Runnable() { 
    @Override 
    public void run() { 
     int width = YOUR_LAYOUT.getMeasuredWidth(); 
     int height = YOUR_LAYOUT.getMeasuredHeight(); 
    } 
}); 
+2

Non so se il post verrà effettivamente eseguito il codice dopo che la vista è già stata creata. Non c'è alcuna garanzia, dal momento che post aggiungerà semplicemente il Runnable che crei a RunQueue, da eseguire dopo la precedente esecuzione della coda sul thread UI. – HendraWD

+4

Al contrario, post() viene eseguito dopo il successivo aggiornamento dell'interfaccia utente, che avviene dopo la creazione della vista. Pertanto, è garantito che verrà eseguito dopo aver effettuato la visualizzazione. – Elliptica

+0

Ho provato questo codice più volte, funziona meglio solo nel thread UI. In un thread in background a volte non funziona. – CoolMind

Problemi correlati