web-dev-qa-db-fra.com

Les options getWidth () et getHeight () de View

Je crée tous les éléments de mon projet Android de manière dynamique. J'essaie d'obtenir la largeur et la hauteur d'un bouton pour pouvoir le faire pivoter. J'essaie simplement d'apprendre à travailler avec le langage Android. Cependant, il retourne 0. 

J'ai fait des recherches et j'ai vu qu'il fallait le faire ailleurs que dans la méthode onCreate(). Si quelqu'un peut me donner un exemple de la façon de le faire, ce serait formidable. 

Voici mon code actuel:

package com.animation;

import Android.app.Activity;
import Android.os.Bundle;
import Android.view.animation.Animation;
import Android.view.animation.LinearInterpolator;
import Android.view.animation.RotateAnimation;
import Android.widget.Button;
import Android.widget.LinearLayout;

public class AnimateScreen extends Activity {


//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LinearLayout ll = new LinearLayout(this);

    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(30, 20, 30, 0);

    Button bt = new Button(this);
    bt.setText(String.valueOf(bt.getWidth()));

    RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2);
    ra.setDuration(3000L);
    ra.setRepeatMode(Animation.RESTART);
    ra.setRepeatCount(Animation.INFINITE);
    ra.setInterpolator(new LinearInterpolator());

    bt.startAnimation(ra);

    ll.addView(bt,layoutParams);

    setContentView(ll);
}

Toute aide est appréciée.

430
ngreenwood6

Vous appelez getWidth() trop tôt. L'interface utilisateur n'a pas encore été dimensionnée et affichée à l'écran.

Quoi qu'il en soit, je doute que vous souhaitiez faire ce que vous faites. Les widgets animés ne modifient pas leurs zones cliquables. Le bouton répondra donc aux clics dans l'orientation d'origine, quelle que soit sa rotation.

Cela étant dit, vous pouvez utiliser une ressource de dimension pour définir la taille du bouton, puis référencer cette ressource de dimension à partir de votre fichier de présentation et de votre code source, pour éviter ce problème.

174
CommonsWare

On peut utiliser 

@Override
 public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);
  //Here you can get the size!
 }
256
Sana

J'ai utilisé cette solution, qui me semble meilleure que onWindowFocusChanged (). Si vous ouvrez un DialogFragment, puis faites pivoter le téléphone, onWindowFocusChanged sera appelé uniquement lorsque l'utilisateur fermera la boîte de dialogue):

    yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            // Ensure you call it only once :
            yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

            // Here you can get the size :)
        }
    });

Edit: comme removeGlobalOnLayoutListener est obsolète, vous devriez maintenant faire:

@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {

    // Ensure you call it only once :
    if(Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.JELLY_BEAN) {
        yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
    else {
        yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }

    // Here you can get the size :)
}
103
Tim Autin

Comme Ian le dit dans ce fil Android Developers :

Quoi qu’il en soit, l’accord est la mise en page du le contenu d'une fenêtre se passe after tous les éléments sont construits et ajoutés à leur parent vues. Cela doit être ainsi, parce que jusqu'à ce que vous sachiez quels composants une vue contient, et ce qu’ils contiennent, et ainsi de suite, il n'y a aucun moyen raisonnable que vous puissiez exposez-le.

En bout de ligne, si vous appelez getWidth () etc. dans un constructeur, il retournera zéro. La procédure consiste à créer tout vos éléments de vue dans le constructeur, puis attendez votre vue Méthode onSizeChanged () à appeler -- c'est la première fois que vous découvrez votre taille réelle, alors vous configurez les tailles de vos éléments d'interface graphique.

Sachez aussi que onSizeChanged () est parfois appelé avec les paramètres de zéro - vérifier pour ce cas, et retournez immédiatement (pour ne pas avoir une division de par zéro lors du calcul de votre mise en page , etc.). Quelque temps plus tard, il sera appelé avec les vraies valeurs.

75
kerem yokuva

Si vous devez obtenir la largeur d'un widget avant qu'il ne soit affiché à l'écran, vous pouvez utiliser getMeasuredWidth () ou getMeasuredHeight ().

myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int width = myImage.getMeasuredWidth();
int height = myImage.getMeasuredHeight();
58
sulu.dev

Je préférerais utiliser OnPreDrawListener() au lieu de addOnGlobalLayoutListener(), car il est appelé plus tôt. 

    view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
    {
        @Override
        public boolean onPreDraw()
        {
            if (view.getViewTreeObserver().isAlive())
                view.getViewTreeObserver().removeOnPreDrawListener(this);

            // put your code here
            return true;
        }
    });
14
Sa Qada

Extension pour obtenir de la hauteur dans Kotlin dynamiquement.

Usage:

view.height { Log.i("Info", "Here is your height:" + it) }

La mise en oeuvre:

fun <T : View> T.height(function: (Int) -> Unit) {
    if (height == 0)
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
                function(height)
            }
        })
    else function(height)
}
4
Renetik

Une doublure si vous utilisez RxJava & RxBindings . Approche similaire sans le passe-partout. Cela résout également le problème de supprimer les avertissements comme dans la réponse de Tim Autin .

RxView.layoutChanges(yourView).take(1)
      .subscribe(aVoid -> {
           // width and height have been calculated here
      });

Ça y est. Pas besoin d'être désabonné, même si jamais appelé.

3
Odys

Peut-être que cela aide quelqu'un:

Créer une fonction d'extension pour la classe View

nom du fichier: ViewExt.kt

fun View.afterLayout(what: () -> Unit) {
    if(isLaidOut) {
        what.invoke()
    } else {
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
                what.invoke()
            }
        })
    }
}

Ceci peut alors être utilisé sur n'importe quelle vue avec:

view.afterLayout {
    do something with view.height
}
1
Pepijn

Si vous utilisez Kotlin

  leftPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {

            override fun onGlobalLayout() {

                if(Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.JELLY_BEAN) {
                    leftPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
                }
                else {
                    leftPanel.viewTreeObserver.removeGlobalOnLayoutListener(this)
                }

                // Here you can get the size :)
                leftThreshold = leftPanel.width
            }
        })
1
Hitesh Sahu

La hauteur et la largeur sont égales à zéro car la vue n'a pas été créée au moment où vous demandez sa hauteur et sa largeur. Une solution la plus simple est

view.post(new Runnable() {
        @Override
        public void run() {
            view.getHeight(); //height is ready
            view.getWidth(); //width is ready
        }
    });

Cette méthode est bonne comparée à d’autres méthodes car elle est courte et nette.

1
Shivam Yadav

Les vues disparues renvoient 0 en hauteur si l'application en arrière-plan .Ce code (1oo% fonctionne)

fun View.postWithTreeObserver(postJob: (View, Int, Int) -> Unit) {
    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            val widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            val heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            measure(widthSpec, heightSpec)
            postJob(this@postWithTreeObserver, measuredWidth, measuredHeight)
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                @Suppress("DEPRECATION")
                viewTreeObserver.removeGlobalOnLayoutListener(this)
            } else {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        }
    })
}

Nous devons attendre que la vue soit dessinée. À cette fin, utilisez OnPreDrawListener. Exemple Kotlin:

val preDrawListener = object : ViewTreeObserver.OnPreDrawListener {

                override fun onPreDraw(): Boolean {
                    view.viewTreeObserver.removeOnPreDrawListener(this)

                    // code which requires view size parameters

                    return true
                }
            }

            view.viewTreeObserver.addOnPreDrawListener(preDrawListener)
0
Artem Botnev