Il problema di base è che devi attendere la fase di disegno per le misurazioni effettive (specialmente con valori dinamici come wrap_content
o match_parent
), ma di solito questa fase non è stata completata onResume()
. Quindi hai bisogno di una soluzione alternativa per aspettare questa fase. Esistono diverse possibili soluzioni a questo:
1. Ascolta gli eventi di disegno / layout: ViewTreeObserver
Un ViewTreeObserver viene attivato per diversi eventi di disegno. Di solito OnGlobalLayoutListener
è quello che vuoi per ottenere la misurazione, quindi il codice nel listener verrà chiamato dopo la fase di layout, quindi le misure sono pronte:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Nota: il listener verrà immediatamente rimosso perché altrimenti si attiverà su ogni evento di layout. Se devi supportare app SDK Lvl <16 utilizzalo per annullare la registrazione del listener:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Aggiungi un file eseguibile alla coda di layout: View.post ()
Non molto noto e la mia soluzione preferita. Fondamentalmente basta usare il metodo post di View con il tuo runnable. Questo in pratica mette in coda il codice dopo la misura, il layout, ecc. Della vista, come affermato da Romain Guy :
La coda eventi dell'interfaccia utente elaborerà gli eventi in ordine. Dopo aver richiamato setContentView (), la coda degli eventi conterrà un messaggio che richiede un inoltro, quindi tutto ciò che pubblichi nella coda avverrà dopo il passaggio del layout
Esempio:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Il vantaggio rispetto a ViewTreeObserver
:
- il tuo codice viene eseguito una sola volta e non è necessario disabilitare Observer dopo l'esecuzione, il che può essere una seccatura
- sintassi meno dettagliata
Riferimenti:
3. Sovrascrivi il metodo onLayout di Views
Ciò è pratico solo in determinate situazioni in cui la logica può essere incapsulata nella vista stessa, altrimenti si tratta di una sintassi piuttosto dettagliata e ingombrante.
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
Ricorda inoltre che onLayout verrà chiamato molte volte, quindi considera attentamente ciò che fai nel metodo o disabilita il codice dopo la prima volta
4. Verificare se è stata eseguita la fase di layout
Se si dispone di codice che viene eseguito più volte durante la creazione dell'interfaccia utente, è possibile utilizzare il seguente metodo lib v4 di supporto:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Restituisce vero se la vista ha attraversato almeno un layout dall'ultima volta in cui è stata collegata o scollegata da una finestra.
Ulteriori: ottenere misurazioni definite staticamente
Se è sufficiente ottenere l'altezza / larghezza definite staticamente, puoi farlo con:
Ma attenzione, questo potrebbe essere diverso dalla larghezza / altezza effettive dopo il disegno. Il javadoc descrive perfettamente la differenza:
La dimensione di una vista è espressa con una larghezza e un'altezza. Una vista in realtà possiede due coppie di valori di larghezza e altezza.
La prima coppia è nota come larghezza misurata e altezza misurata. Queste dimensioni definiscono la dimensione massima di una vista all'interno del padre (per ulteriori dettagli, vedere Layout). Le dimensioni misurate possono essere ottenute chiamando getMeasuredWidth () e getMeasuredHeight ().
La seconda coppia è semplicemente conosciuta come larghezza e altezza, o talvolta larghezza e altezza del disegno. Queste dimensioni definiscono la dimensione effettiva della vista sullo schermo, al momento del disegno e dopo il layout. Questi valori possono, ma non devono, essere diversi dalla larghezza e dall'altezza misurate. La larghezza e l'altezza possono essere ottenute chiamando getWidth () e getHeight ().