606 votes

getWidth() retourne 0

Je suis la création de tous les éléments de mon projet android de manière dynamique. Je suis en train d'obtenir la largeur et la hauteur du bouton, de sorte que je peux tourner le bouton de autour de. Juste essayer d'apprendre à travailler avec l'android de la langue. Cependant, il est de retour en 0.

J'ai fait quelques recherches et je continue à voir que ce qui doit être fait dans un endroit autre que l' onCreate() méthode. Si quelqu'un pouvait me donner un exemple de comment le faire, ce serait super.

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.

970voto

for3st Points 2727

Le problème de base est que vous vous avez à attendre pour le tirage au sort de la phase pour les mesures réelles (en particulier avec la dynamique des valeurs comme l' wrap_content ou match_parent), mais généralement, cette phase n'a pas été terminé en hausse de onResume(). Si vous avez besoin d'une solution de contournement pour l'attente pour cette phase. Il y a, ce sont les différentes solutions possibles à cela:


1. Écouter Dessin/Mise en page des Événements: ViewTreeObserver

Un ViewTreeObserver est exclu pour les différentes dessin événements. Généralement l' OnGlobalLayoutListener est ce que vous voulez pour obtenir la mesure, de sorte que le code de l'auditeur sera appelé après le schéma de phase, de sorte que les mesures sont prêts:

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    view.getHeight(); //height is ready
                }
            });
        }
    });

Mais méfiez-vous que ce sera appelée à chaque fois que quelque chose se relooké (e.g si vous définissez un point de vue invisible ou similaire), donc n'oubliez pas de supprimer cette écoute si vous en avez le plus besoin avec:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) dans le SDK Lvl < 16

ou

public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) dans le SDK Lvl >= 16


2. Ajouter un exécutable de la mise en page de la file d'attente: la Vue.post()

Pas très bien connue et ma solution préférée. Fondamentalement, suffit d'utiliser le point de Vue de la méthode post avec votre propre exécutable. Au fond, les files d'attente de votre code après le point de vue de la mesure, mise en page, etc. comme indiqué par Romain Guy:

L'INTERFACE utilisateur de la file d'attente d'événements va traiter les événements dans l'ordre. Après setContentView() est appelée, la file d'attente d'événements contiendra un message en demandant une nouvelle disposition, de sorte que vous publiez à la file d'attente va se passer après la passe de mise en page

Exemple:

final View view=//smth;
...
view.post(new Runnable() {
            @Override
            public void run() {
                view.getHeight(); //height is ready
            }
        });

L'avantage par rapport ViewTreeObserver:

  • votre code est exécutée une seule fois et vous n'avez pas à désactiver l'Observateur après l'exécution qui peut être embêtant
  • moins verbeux syntaxe

Références:


3. Écraser les points de Vue de la Méthode onLayout

Ce n'est pratique dans certains cas, lorsque l'logique peut être moduled dans la vue elle-même, sinon c'est assez verbeux et syntaxe lourde.

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

Aussi l'esprit, que onLayout sera appelé de nombreuses fois, être attentif à ce que vous faites dans la méthode, ou de désactiver votre code après la première fois


Supplémentaires: Arriver staticly les mesures définies

Si il suffit d'obtenir l'définis de manière statique hauteur/largeur, tu peux faire ça avec:

Mais vous l'esprit, qui peut être différente de ce à la largeur/hauteur après le tirage. La javadoc décrit la différence parfaitement:

De la taille d'un point de vue est exprimé avec une largeur et une hauteur. Vue effectivement posséder deux paires de valeurs de largeur et hauteur.

La première paire est connu comme mesuré la largeur et la hauteur mesurée. Ces dimensions définir comment grand une vue veut être à l'intérieur de ses parents (voir Mise en page pour plus de détails.) Les dimensions mesurées peuvent être obtenus par l'appel de getMeasuredWidth() et getMeasuredHeight().

La seconde paire est simplement connu comme la largeur et la hauteur, ou parfois le dessin de la largeur et de la hauteur de dessin. Ces dimensions définir le réel la taille de la vue sur l'écran, au moment du dessin et après sa mise en page. Ces les valeurs peuvent, mais ne doivent pas, être différente de la largeur mesurée et la hauteur. La largeur et la hauteur peuvent être obtenues en appelant getWidth() et getHeight().

268voto

Sana Points 3743

Nous pouvons utiliser

223voto

CommonsWare Points 402670

Vous appelez getWidth() trop tôt. L'INTERFACE utilisateur n'a pas été dimensionnées et disposées sur l'écran mais.

Je doute que vous voulez faire ce que vous faites, de toute façon -- widgets animés ne pas changer leurs zones cliquables, et de sorte que le bouton de toujours répondre aux clics dans l'orientation d'origine, indépendamment de la façon dont il a tourné.

Cela étant dit, vous pouvez utiliser une dimension de ressource pour définir la taille du bouton, puis de référence de la dimension des ressources à partir de votre fichier de mise en page et de votre code source, afin d'éviter ce problème.

118voto

Tim Points 999

J'ai utilisé cette solution, que je pense est mieux que onWindowFocusChanged (). Si vous ouvrez un DialogFragment, puis faites pivoter le téléphone, onWindowFocusChanged sera appelé uniquement lorsque l'utilisateur ferme 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 :)
        }
    });
 

76voto

kerem yokuva Points 541

Comme Ian unis dans cette Développeurs Android thread:

De toute façon, l'affaire est que la disposition de la contenu d'une fenêtre qui se passe après tous les éléments sont construits et ajoutent à leur parent les vues. Il doit être de cette façon, parce que jusqu'à ce que vous savez quels sont les composants d'une Vue contient, et ce qu'ils contiennent, et donc, il n'y a pas de meilleure façon, vous pouvez étalez-la.

En bout de ligne, si vous appelez getWidth() etc. dans un constructeur, il sera de retour zéro. La procédure est de créer tous les votre affichage des éléments dans le constructeur, ensuite, attendre pour votre Vue onSizeChanged() la méthode pour être appelé. c'est alors que vous devez d'abord trouver votre taille réelle, de sorte que lorsque vous configurez la taille des éléments de votre interface.

Sachez aussi que onSizeChanged() est parfois appelé avec des paramètres de zéro -- check pour ce cas, et retourner immédiatement (si vous n'obtenez pas une division par zéro dans le calcul de votre mise en page, etc.). Quelques temps plus tard, il sera appelé avec les valeurs réelles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X