Je crée dynamiquement tous les éléments de mon projet Android. J'essaie d'obtenir la largeur et la hauteur d'un bouton afin de pouvoir le faire pivoter. J'essaie juste d'apprendre à travailler avec la langue Android. Cependant, il renvoie 0.
J'ai fait des recherches et j'ai vu que cela devait être fait ailleurs que dans la onCreate()
méthode. Si quelqu'un peut me donner un exemple de la façon de procéder, 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.
la source
Le problème de base est que vous devez attendre la phase de dessin pour les mesures réelles (en particulier avec des valeurs dynamiques comme
wrap_content
oumatch_parent
), mais généralement cette phase n'est pas terminéeonResume()
. Vous avez donc besoin d'une solution de contournement pour attendre cette phase. Il existe différentes solutions possibles à cela:1. Écoutez les événements Draw / Layout: ViewTreeObserver
Un ViewTreeObserver est déclenché pour différents événements de dessin. Habituellement,
OnGlobalLayoutListener
c'est ce que vous voulez pour obtenir la mesure, donc le code dans l'auditeur sera appelé après la phase de mise en page, donc les mesures sont prêtes:Remarque: l'écouteur sera immédiatement supprimé car sinon, il se déclenchera à chaque événement de mise en page. Si vous devez prendre en charge les applications SDK Lvl <16, utilisez-le pour désinscrire l'auditeur:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Ajoutez un exécutable à la file d'attente de mise en page: View.post ()
Pas très connu et ma solution préférée. Fondamentalement, utilisez simplement la méthode de publication de View avec votre propre exécutable. Cela met essentiellement votre code en file d'attente après la mesure, la disposition, etc. de la vue, comme indiqué par Romain Guy :
Exemple:
L'avantage sur
ViewTreeObserver
:Références:
3. Écraser la méthode onLayout des vues
Ceci n'est pratique que dans certaines situations où la logique peut être encapsulée dans la vue elle-même, sinon c'est une syntaxe assez bavarde et encombrante.
Sachez également que onLayout sera appelé plusieurs fois, alors pensez à ce que vous faites dans la méthode ou désactivez votre code après la première fois
4. Vérifiez si la phase de mise en page a été franchie
Si vous avez du code qui s'exécute plusieurs fois lors de la création de l'interface utilisateur, vous pouvez utiliser la méthode de support v4 lib suivante:
Supplémentaire: Obtention de mesures définies statiquement
S'il suffit juste d'obtenir la hauteur / largeur définie statiquement, vous pouvez simplement le faire avec:
View.getMeasuredWidth()
View.getMeasuredHeigth()
Mais attention, cela peut être différent de la largeur / hauteur réelle après le dessin. Le javadoc décrit parfaitement la différence:
la source
runOnUiThread(new Runnable() {...}
. Actuellement , j'utilise une variante de la 1ère méthode:addOnLayoutChangeListener
. N'oubliez pas de le supprimer puis à l'intérieur: removeOnLayoutChangeListener. Il fonctionne également à partir du fil d'arrière-plan.android:visibility="gone"
et sur l'autre projet la propriété de visibilité étaitinvisible
. Si la visibilité estgone
la largeur sera toujours 0.On peut utiliser
la source
J'ai utilisé cette solution, qui je pense est meilleure que sur 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):
Edit: comme removeGlobalOnLayoutListener est déconseillé, vous devriez maintenant faire:
la source
Comme l'indique Ian dans ce fil de discussion Android Developers :
la source
Bottom line, if you call getWidth() etc. in a constructor, it will return zero.
c'est un bingo. La racine de mes problèmes.Si vous devez obtenir la largeur d'un widget avant qu'il ne s'affiche à l'écran, vous pouvez utiliser getMeasuredWidth () ou getMeasuredHeight ().
la source
Je préfère utiliser
OnPreDrawListener()
au lieu deaddOnGlobalLayoutListener()
, car il est appelé un peu plus tôt que les autres auditeurs.la source
return false
moyens d' annuler le passage de dessin en cours . Pour continuer, à lareturn true
place.Une extension Kotlin pour observer sur la mise en page globale et effectuer une tâche donnée lorsque la hauteur est prête dynamiquement.
Usage:
La mise en oeuvre:
la source
AndroidX dispose de plusieurs fonctions d'extension qui vous aident dans ce type de travail, à l'intérieur
androidx.core.view
Vous devez utiliser Kotlin pour cela.
Celui qui convient le mieux ici est
doOnLayout
:Dans votre exemple:
Dépendance:
androidx.core:core-ktx:1.0.0
la source
Un liner si vous utilisez RxJava & RxBindings . Approche similaire sans passe-partout. Cela résout également le piratage pour supprimer les avertissements comme dans la réponse de Tim Autin .
Ça y est. Pas besoin de se désinscrire, même si jamais appelé.
la source
Cela se produit parce que la vue a besoin de plus de temps pour être gonflée. Ainsi, au lieu d'appeler
view.width
etview.height
sur le thread principal, vous devez utiliserview.post { ... }
pour vous assurer que votreview
a déjà été gonflé. À Kotlin:En Java , vous pouvez également appeler
getWidth()
etgetHeight()
méthodes dans uneRunnable
et passer laRunnable
à laview.post()
méthode.la source
.post
ne garantit pas la vue à présenter.La hauteur et la largeur sont nulles 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
Cette méthode est bonne par rapport à d'autres méthodes car elle est courte et nette.
la source
Peut-être que cela aide quelqu'un:
Créer une fonction d'extension pour la classe View
Cela peut ensuite être utilisé sur n'importe quelle vue avec:
la source
La réponse avec
post
est incorrecte, car la taille peut ne pas être recalculée.Une autre chose importante est que la vue et tous ses ancêtres doivent être visibles . Pour cela j'utilise une propriété
View.isShown
.Voici ma fonction kotlin, qui peut être placée quelque part dans les utils:
Et l'utilisation est:
la source
Si vous utilisez Kotlin
la source
Les vues disparues renvoient 0 comme hauteur si l'application est en arrière-plan. Ce mon code (1oo% fonctionne)
la source
Nous devons attendre que la vue soit tracée. À cette fin, utilisez OnPreDrawListener. Exemple de Kotlin:
la source