67 Stimmen

Android: Höhe einer Ansicht ermitteln, bevor sie gezeichnet wird

Für eine Animation muss ich die Höhe einer Ansicht kennen. Das Problem ist, dass die getHeight()-Methode immer 0 zurückgibt, es sei denn, der View ist gezeichnet. Gibt es also eine Möglichkeit, die Höhe zu ermitteln, ohne sie zu zeichnen?

In diesem Fall ist die Ansicht ein LinearLayout.

EDIT: Ich versuche, die Expand Animation von https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.java

Damit möchte ich einige weitere Informationen für ein Listenelement erweitern. Ich war nicht in der Lage, den gleichen Effekt über xml zu erreichen. Im Moment funktioniert die Animation nur, wenn man die Größe des Layouts kennt, bevor man es zeichnet.

139voto

Jim Baca Punkte 5972

Klingt, als wollten Sie die Höhe ermitteln, aber die Ansicht ausblenden, bevor sie sichtbar ist.

Stellen Sie die Sichtbarkeit in der Ansicht zunächst auf sichtbar oder unsichtbar ein (nur damit eine Höhe erzeugt wird). Machen Sie sich keine Sorgen, wir werden es im Code wie unten gezeigt auf unsichtbar/weg ändern:

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 );
        }

});

34voto

Hermann Klecker Punkte 13881

Ich hatte ein ähnliches Problem mit einer ähnlichen Situation.

Ich musste eine Anmiation erstellen, für die ich die Höhe der view die der Animation unterliegt. Innerhalb dieser view die ein LinearLayout kann eine untergeordnete Ansicht des Typs TextView . Das TextView ist mehrzeilig und die Anzahl der tatsächlich benötigten Zeilen variiert.

Was immer ich getan habe, ich habe nur die gemessene Höhe für die Ansicht, als ob die TextView hat nur eine Zeile zu füllen. Kein Wunder, dass dies jedes Mal gut funktionierte, wenn der Text kurz genug für eine einzige Zeile war, aber nicht, wenn der Text länger als eine Zeile war.

Ich habe mir diese Antwort überlegt: https://stackoverflow.com/a/6157820/854396 Aber das hat bei mir nicht so gut funktioniert, weil ich nicht in der Lage bin, auf die eingebettete TextView direkt von hier aus. (Ich hätte allerdings auch den Baum der untergeordneten Ansichten durchgehen können).

Schauen Sie sich meinen Code an, denn er funktioniert im Moment:

view ist die Ansicht, die animiert werden soll. Sie ist eine LinearLayout (Die endgültige Lösung wird hier etwas typsicherer sein) this ist eine benutzerdefinierte Ansicht, die Folgendes enthält view und erbt von LinearLayout zu.

   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 );
   }

Das war fast alles, aber ich habe noch einen Fehler gemacht. Innerhalb der View-Hierarchie gibt es zwei benutzerdefinierte Views, die Unterklassen von LinearLayout und deren xml wird mit einer merge Tag als xml Root Tag. Innerhalb eines dieser merge Tags, die ich übersehen habe, um die android:orientation Attribut zu vertical . Das störte das Layout selbst nicht allzu sehr, denn in diesem zusammengefassten ViewGroup war nur ein Kind ViewGroup und deshalb konnte ich die falsche Ausrichtung auf dem Bildschirm nicht wirklich sehen. Aber sie war da und hat die Logik der Layout-Messung ein wenig durchbrochen.

Zusätzlich zu den oben genannten Punkten kann es erforderlich sein, alle Auffüllungen loszuwerden, die mit LinearLayout s und Unterklassen innerhalb der Ansichtshierarchie. Ersetzen Sie sie durch Ränder, auch wenn Sie ein anderes Layout darum wickeln müssen, damit es gleich aussieht.

16voto

Fixpoint Punkte 9251

Technisch gesehen, können Sie measure Methode auf die Ansicht anwenden und dann die Höhe über getMeasureHeight . Siehe dies für weitere Informationen: https://developer.Android.com/guide/topics/ui/how-Android-draws.html . Sie müssen ihm eine MeasureSpec Allerdings.

In der Realität wird die Größe der Ansicht jedoch von ihrem übergeordneten Layout beeinflusst, so dass sie möglicherweise eine andere Größe hat, als sie tatsächlich gezeichnet wird.

Sie können auch versuchen, mit RELATIVE_TO_SELF Werte in Ihren Animationen.

12voto

Anubhav Punkte 1636
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();
}

8voto

j2emanue Punkte 56131

Messen Sie es einfach selbst, wenn die Größe nicht von den Eltern bestimmt wird:

Hier ist eine Kotlin-Erweiterung für die Ansicht, die dies für Sie immer tut:

fun View.getMeasurments(): Pair<Int, Int> {
    measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    val width = measuredWidth
    val height = measuredHeight
    return width to height
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X