2012-03-05 13 views
38

Per un'animazione ho bisogno di conoscere l'altezza da una vista. Il problema è che il metodo getHeight() restituisce sempre 0 a meno che la Vista non venga disegnata. Quindi c'è un modo per ottenere l'altezza senza disegnarla?Android: ottieni l'altezza di una vista prima che venga disegnata.

In questo caso, la vista è un LinearLayout.

EDIT: cerco di adattare l'animazione espandersi da https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.java

Con esso voglio ampliare alcune informazioni per una voce di elenco. Non ero in grado di ottenere lo stesso effetto tramite xml. Al momento l'animazione funziona solo quando si conosce la dimensione del layout prima di disegnarla.

risposta

10

Tecnicamente, è possibile chiamare il metodo measure sulla vista e quindi ottenere la sua altezza tramite getMeasureHeight. Vedi questo per maggiori informazioni: https://developer.android.com/guide/topics/ui/how-android-draws.html. Avrai bisogno di dargli un MeasureSpec però.

Ma in realtà, la dimensione della vista è influenzata dal layout principale, quindi è possibile che si ottenga una dimensione diversa rispetto a quando è effettivamente disegnata.

Inoltre, è possibile provare a utilizzare i valori RELATIVE_TO_SELF nelle animazioni.

+0

Infatti l'altezza restituita da getMeasuredSpec è diversa. Al momento 34 vs 137. Ho modificato il mio primo messaggio con qualche altra informazione. – anonymous

+1

Vedi la mia nuova risposta. – Fixpoint

+0

Questa risposta è la risposta giusta, ma la mancanza di codice è la semplice ragione per meno upvotes. – Warpzit

-5

Si potrebbe provare a iniziare con la vista visibile, e quindi aggiungere qualcosa di simile:

view.post(new Runnable() {  
    @Override 
    public void run() { 
     // hide view here so that its height has been already computed 
     view.setVisibility(View.GONE); 
    } 
}); 

Ora, quando si chiamerà view.getHeight() deve restituire l'altezza che ci si aspetta.

Non sono sicuro che sia davvero un buon modo per farlo, ma almeno dovrebbe funzionare.

+0

Se si esegue questa operazione, prima verrà visualizzata la vista e quindi verrà eseguita questa operazione. Nel caso in cui vogliamo impostare i parametri in base a parametri di viste, allora vorremmo fare qualcos'altro. – lokoko

0

Ok, per quanto riguarda il post aggiornato, ecco cosa ti aiuterà: metodo Animation#initialize. Dovresti solo mettere l'inizializzazione lì al posto del costruttore, e avrai tutte le dimensioni che ti servono.

+0

Hm ... non capisco. Lì anche l'altezza è 0, a meno che la Vista non sia visibile e non sia sparita. – anonymous

+2

Provare a usare "INVISIBILE" invece di "GONE". – Fixpoint

+0

Potrebbe essere un buon suggerimento. Ma ora l'animazione non inizia immediatamente. A volte prima di tutto se scorro o interagisco con l'interfaccia utente in qualche modo. – anonymous

112

Sembra che tu desideri ottenere l'altezza ma nascondere la vista prima che sia visibile.

Avere la visibilità nella vista impostata su visibile o invisibile per iniziare (solo in modo che venga creata un'altezza). Non preoccupatevi cambieremo a invisibile/andato nel codice come illustrato di seguito:

private int mHeight = 0; 
private View mView; 

class... 

// onCreate or onResume or onStart ... 
mView = findViewByID(R.id.someID); 
mView.getViewTreeObserver().addOnGlobalLayoutListener( 
    new OnGlobalLayoutListener(){ 

     @Override 
     public void onGlobalLayout() { 
      // gets called after layout has been done but before display 
      // so we can get the height then hide the view 


      mHeight = mView.getHeight(); // Ahaha! Gotcha 

      mView.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      mView.setVisibility(View.GONE); 
     } 

}); 
+9

Grazie, funziona! Solo una piccola aggiunta: removeGlobalOnLayoutListener() è deprecato dal livello API 16, è stato sostituito da removeOnGlobalLayoutListener() –

+0

Grazie mi ha aiutato molto. la misurazione delle visualizzazioni è bacata. –

+1

Grazie per questo suggerimento, ha funzionato molto bene. Nota a margine, il fatto che il nome dell'argomento per removeOnGlobalLayoutListener sia "vittima" è fantastico. – Silmarilos

12

ho avuto un problema simile con una situazione simile.

Ho dovuto creare un'animazione per cui ho richiesto l'altezza dello view soggetto all'animazione. All'interno di tale view, che è un LinearLayout potrebbe essere una vista secondaria di tipo TextView. Che TextView è una linea multipla e il numero di righe effettivamente richiesto varia.

Qualunque cosa facessi, ho appena ottenuto l'altezza misurata per la vista, come se lo TextView avesse solo una linea da riempire. Non c'è da meravigliarsi se questo ha funzionato bene ogni volta che il testo è risultato abbastanza breve per una singola riga, ma non ha funzionato quando il testo era più lungo.

Ho considerato questa risposta: https://stackoverflow.com/a/6157820/854396 Ma quello non ha funzionato troppo bene per me perché non sono in grado di accedere allo TextView incorporato direttamente da qui. (Avrei potuto iterato anche se l'albero della vista dei bambini però.)

Dai un'occhiata alla mia codice come funziona, per ora:

view è la vista che deve essere animato. È un LinearLayout (La soluzione finale sarà un po 'più di tipo salva qui) this è una vista personalizzata che contiene view e eredita anche da LinearLayout.

private void expandView(final View view) { 

     view.setVisibility(View.VISIBLE); 

     LayoutParams parms = (LayoutParams) view.getLayoutParams(); 
     final int width = this.getWidth() - parms.leftMargin - parms.rightMargin; 

     view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), 
       MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 

     final int targetHeight = view.getMeasuredHeight(); 

     view.getLayoutParams().height = 0; 

     Animation anim = new Animation() { 
     @Override 
     protected void applyTransformation(float interpolatedTime, Transformation trans) { 
      view.getLayoutParams().height = (int) (targetHeight * interpolatedTime); 
      view.requestLayout(); 
     } 

     @Override 
     public boolean willChangeBounds() { 
      return true; 
     } 
     }; 

     anim.setDuration(ANIMATION_DURATION); 
     view.startAnimation(anim); 
    } 

Questo era quasi ma ho fatto un altro errore. All'interno della gerarchia delle viste sono coinvolte due viste personalizzate che sono sottoclassi di LinearLayout e il loro xml è unito con un tag merge come tag radice xml. All'interno di uno di questi tag merge ho trascurato di impostare l'attributo android:orientation su vertical. Questo non ha preoccupato troppo per il layout stesso, perché all'interno di questo unificato ViewGroup era solo un figlio ViewGroup e quindi non ho potuto effettivamente vedere l'orientamento sbagliato sullo schermo. Ma era lì e in qualche modo ha rotto un po 'questa logica di misura del layout.

In aggiunta a quanto sopra, potrebbe essere necessario eliminare tutti i padding associati a LinearLayout s e sottoclassi all'interno della gerarchia di viste. Sostituiscili con i margini, anche se devi avvolgere un altro layout intorno per renderlo uguale.

+0

Grazie! Ho perso molte ore con questo. –

0
static void getMeasurments(View v) { 

    v.measure(View.MeasureSpec.makeMeasureSpec(PARENT_VIEW.getWidth(), 
     View.MeasureSpec.EXACTLY), 
     View.MeasureSpec.makeMeasureSpec(0, 
     View.MeasureSpec.UNSPECIFIED)); 

    final int targetHeight = v.getMeasuredHeight(); 
    final int targetWidth = v.getMesauredWidth(); 
} 
Problemi correlati