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.
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.
On peut utiliser
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//Here you can get the size!
}
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 :)
}
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.
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();
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;
}
});
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)
}
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é.
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
}
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
}
})
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.
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)