web-dev-qa-db-fra.com

Android: obtenez la hauteur d'une vue avant qu'elle ne soit dessinée

Pour une animation, j'ai besoin de connaître la hauteur d'une vue. Le problème est que la méthode getHeight () retourne toujours 0 sauf si la vue est dessinée. Existe-t-il un moyen d'obtenir de la hauteur sans la dessiner?

Dans ce cas, la vue est un LinearLayout.

EDIT: J'essaie d'adapter l'animation développée à partir de https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.Java

Avec cela, je veux développer plus d'informations pour un élément de liste. Je n'ai pas pu obtenir le même effet via xml. Pour le moment, l'animation ne fonctionne que lorsque vous connaissez la taille de la mise en page avant de la dessiner.

46
anonymous

On dirait que vous voulez obtenir la hauteur mais masquer la vue avant qu'elle ne soit visible.

Définissez d'abord la visibilité dans la vue sur visible ou invisible (juste pour créer une hauteur). Ne vous inquiétez pas, nous le changerons en invisible/disparu dans le code comme indiqué ci-dessous:

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

});
124
Jim Baca

J'ai eu un problème similaire avec une situation similaire.

J'ai dû créer une animation pour laquelle j'avais besoin de la hauteur du view qui est soumis à l'animation. Dans cette view, qui est une LinearLayout, il peut y avoir une vue enfant de type TextView. Cela TextView est multi-lignes et le nombre de lignes réellement requis varie.

Quoi que je fasse, je viens d'obtenir la hauteur mesurée pour la vue comme si le TextView n'avait qu'une seule ligne à remplir. Pas étonnant que cela a bien fonctionné à chaque fois que le texte était suffisamment court pour une seule ligne, mais cela a échoué lorsque le texte était plus long qu'en ligne.

J'ai considéré cette réponse: https://stackoverflow.com/a/6157820/854396 Mais celle-là n'a pas trop bien fonctionné pour moi car je ne suis pas en mesure d'accéder à l'embarqué TextView directement d'ici. (J'aurais pu faire une itération dans l'arborescence des vues d'enfant cependant.)

Jetez un œil à mon code tel qu'il fonctionne pour l'instant:

view est la vue à animer. Il s'agit d'un LinearLayout (la solution finale sera un peu plus de type sauf ici) this est une vue personnalisée qui contient view et hérite également de 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 );
   }

C'était presque ça, mais j'ai fait une autre erreur. Dans la hiérarchie des vues, deux vues personnalisées sont impliquées, qui sont des sous-classes de LinearLayout et leur xml est fusionné avec une balise merge en tant que balise racine xml. Dans l'une de ces balises merge, j'ai négligé de définir le Android:orientation attribut à vertical. Cela ne dérangeait pas trop pour la mise en page elle-même, car dans cette fusion ViewGroup était juste un enfant ViewGroup et donc je ne pouvais pas vraiment voir la mauvaise orientation à l'écran. Mais il était là et a quelque peu brisé cette logique de mesure de la disposition.

En plus de ce qui précède, il peut être nécessaire de se débarrasser de tous les remplissages associés aux LinearLayout et aux sous-classes dans la hiérarchie des vues. Remplacez-les par des marges, même si vous devez en entourer un autre pour le rendre identique.

21
Hermann Klecker

Techniquement, vous pouvez appeler la méthode measure sur la vue, puis obtenir sa hauteur via getMeasureHeight. Voir ceci pour plus d'informations: https://developer.Android.com/guide/topics/ui/how-Android-draws.html . Vous devrez cependant lui donner un MeasureSpec.

Mais en réalité, la taille de la vue est influencée par sa disposition parentale, vous pouvez donc obtenir une taille différente de celle lorsqu'elle est réellement dessinée.

Vous pouvez également essayer d'utiliser RELATIVE_TO_SELF valeurs dans vos animations.

12
Fixpoint
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();
}
4
Anubhav

Ok, concernant la publication mise à jour, voici ce qui vous aidera: Animation # initialize méthode. Vous devriez simplement mettre l'initialisation à la place du constructeur, et vous aurez toutes les tailles dont vous avez besoin.

0
Fixpoint

mesurez-le vous-même si le parent ne détermine pas sa taille:

voici une extension kotlin en vue de le faire pour vous toujours:

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