90 votes

Une façon autorisée de surcharger onMeasure() ?

Quelle est la manière correcte de remplacer onMeasure() ? J'ai vu différentes approches. Par exemple, Développement professionnel d'Android utilise MeasureSpec pour calculer les dimensions, puis se termine par un appel à setMeasuredDimension(). Par exemple :

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
}

D'autre part, selon ce poste La méthode "correcte" consiste à utiliser MeasureSpec et à appeler setMeasuredDimensions(), suivi par un appel à setLayoutParams(), et se terminant par un appel à super.onMeasure(). Par exemple :

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

Alors, quelle est la bonne méthode ? Aucune des deux approches n'a fonctionné à 100% pour moi.

Je suppose que ce que je demande vraiment, c'est si quelqu'un connaît un tutoriel qui explique onMeasure(), la disposition, les dimensions des vues enfant, etc.

17 votes

Avez-vous trouvé la réponse utile/ correcte ? pourquoi ne pas l'indiquer comme suit le site réponse ?

70voto

Grimmace Points 1872

Les autres solutions ne sont pas complètes. Elles peuvent fonctionner dans certains cas, et constituent un bon point de départ, mais leur efficacité n'est pas garantie.

Lorsque onMeasure est appelé, vous pouvez ou non avoir le droit de changer la taille. Les valeurs qui sont passées à votre onMeasure ( widthMeasureSpec , heightMeasureSpec ) contiennent des informations sur ce que votre enfant est autorisé à faire. Il existe actuellement trois valeurs :

  1. MeasureSpec.UNSPECIFIED - Vous pouvez être aussi grand que vous le souhaitez.
  2. MeasureSpec.AT_MOST - Aussi grand que vous le souhaitez (jusqu'à la taille spécifiée). parentWidth dans votre exemple.
  3. MeasureSpec.EXACTLY - Pas de choix. Les parents ont choisi.

Cela permet à Android d'effectuer plusieurs passages pour trouver la bonne taille pour chaque article, cf. aquí pour plus de détails.

Si vous ne suivez pas ces règles, le succès de votre approche n'est pas garanti.

Par exemple, si vous voulez vérifier si vous êtes autorisé à modifier la taille, vous pouvez procéder comme suit :

final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

Grâce à ces informations, vous saurez si vous pouvez modifier les valeurs comme dans votre code. Ou si vous devez faire quelque chose de différent. Une façon simple et rapide de déterminer la taille souhaitée est d'utiliser l'une des méthodes suivantes :

int resolveSizeAndState (int size, int measureSpec, int childMeasuredState)

int resolveSize (int size, int measureSpec)

Si la première n'est disponible que sur Honeycomb, la seconde l'est sur toutes les versions.

Remarque : Vous pouvez constater que resizeWidth o resizeHeight sont toujours fausses. J'ai trouvé que c'était le cas si je demandais MATCH_PARENT . J'ai pu résoudre ce problème en demandant WRAP_CONTENT sur ma maquette parent et ensuite, pendant la phase UNSPECIFIED, demander une taille de Integer.MAX_VALUE . Ce faisant, vous obtenez la taille maximale autorisée par votre parent lors du prochain passage par onMeasure.

39voto

satur9nine Points 3901

La documentation fait autorité en la matière : http://developer.Android.com/guide/topics/ui/how-Android-draws.html y http://developer.Android.com/guide/topics/ui/custom-components.html

Pour résumer : à la fin de votre commande prioritaire onMeasure vous devez appeler la méthode setMeasuredDimension .

Vous ne devez pas appeler super.onMeasure après avoir appelé setMeasuredDimension qui effacera tout ce que vous avez défini. Dans certaines situations, vous pourriez vouloir appeler la fonction super.onMeasure d'abord et ensuite modifier les résultats en appelant setMeasuredDimension .

N'appelez pas setLayoutParams sur onMeasure . La mise en page se fait lors d'un deuxième passage après la mesure.

0 votes

D'après mon expérience, si je surcharge onMeasure sans appeler super.onMeasure, OnLayout n'est pas appelé sur les vues enfant.

0voto

Kyle O. Points 48

Si la modification de la taille des vues à l'intérieur de onMeasure tout ce dont vous avez besoin est le setMeasuredDimension appel. Si vous modifiez la taille en dehors de onMeasure vous devez appeler setLayoutParams . Par exemple, changer la taille d'une vue de texte lorsque le texte est modifié.

0 votes

Vous pouvez toujours appeler setMinWidth() et setMaxWidth() et laisser le onMeasure standard s'en charger. J'ai trouvé qu'il était préférable de ne pas appeler setLayoutParams à l'intérieur d'une classe de vue personnalisée. Il est vraiment utilisé pour les ViewGroups ou les activités pour remplacer le comportement de la vue enfant.

0voto

Aviral Points 471

Cela dépend du contrôle que vous utilisez. Les instructions de la documentation fonctionnent pour certains contrôles (TextView, Button, ...), mais pas pour d'autres (LinearLayout, ...). La méthode qui a très bien fonctionné pour moi est d'appeler le super une fois que j'ai terminé. Basé sur l'article dans le lien ci-dessous.

http://humptydevelopers.blogspot.in/2013/05/Android-view-overriding-onmeasure.html

0voto

Yuli Matsai Points 163

Voici comment j'ai résolu le problème :

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        ....

        setMeasuredDimension( measuredWidth, measuredHeight );

        widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY );
        heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

De plus, il était nécessaire que le composant ViewPager

3 votes

Ce n'est pas une bonne solution. super.onMeasure effacera les dimensions définies à l'aide de setMeasuredDimension .

0 votes

@tomrozb ce n'est pas humptydevelopers.com/2013/05/ et vous pouvez vérifier les sources d'Android

0 votes

@YuliReiri : Une solution parfaite !

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