视图的getWidth()和getHeight()返回0

我正在dynamic创build我的android项目中的所有元素。 我想获得一个button的宽度和高度,以便我可以旋转该button。 我只是想学习如何使用android语言。 但是,它返回0。

我做了一些研究,我发现它需要在onCreate()方法以外的地方完成。 如果有人能给我一个如何做的例子,那将是很棒的。

这是我现在的代码:

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

任何帮助表示赞赏。

Solutions Collecting From Web of "视图的getWidth()和getHeight()返回0"

您正在调用getWidth()太早。 用户界面的大小和布局尚未完成。

无论如何,我怀疑你是否想做自己正在做的事情 – 被animation化的小部件不会改变它们的可点击区域,因此无论它如何旋转,button仍然会以原始方向响应点击。

也就是说,您可以使用维度资源来定义button大小,然后从布局文件和源代码中引用该维度资源,以避免此问题。

基本的问题是,你必须等待实际测量的绘图阶段(特别是dynamic值,如wrap_contentmatch_parent ),但通常这个阶段还没有完成onResume() 。 所以你需要一个解决方法来等待这个阶段。 有一个不同的可能的解决scheme:

1.听绘图/布局事件:ViewTreeObserver

ViewTreeObserver被不同的绘图事件触发。 通常OnGlobalLayoutListener就是你想要获得测量结果的,所以监听器中的代码将在布局阶段之后被调用,所以测量已经准备好了:

 view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); view.getHeight(); //height is ready } }); 

注意:侦听器将被立即移除,否则它将触发每个布局事件。 如果您必须支持应用程序SDK Lvl <16,请使用此操作取消注册侦听器:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

2.添加一个可运行的布局队列:View.post()

不是很知名,我最喜欢的解决scheme。 基本上只要使用View的post方法和你自己的runnable。 这就像罗曼·盖伊 ( Romain Guy)所说的那样,在视图的度量,布局等之后,

UI事件队列将按顺序处理事件。 在调用setContentView()之后,事件队列将包含一条消息,要求重新布局,所以在布局过后,任何发布到队列中的内容都将发生

例:

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

ViewTreeObserver相比的优势:

  • 你的代码只执行一次,你不必在执行后禁用Observer,这可能是一个麻烦
  • 没有详细的语法

参考文献:

3.覆盖视图的onLayout方法

这只有在逻辑可以被封装在视图本身的情况下才是实用的,否则这是一个非常繁琐和繁琐的语法。

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

另外请注意,onLayout会被多次调用,所以要考虑你在这个方法中做了什么,或者在第一次之后禁用你的代码

4.检查是否已经通过布局阶段

如果您在创buildui时有多次执行的代码,则可以使用以下支持v4 lib方法:

 View viewYouNeedHeightFrom = ... ... if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) { viewYouNeedHeightFrom.getHeight(); } 

如果视图自上次连接到窗口或从窗口分离后至less经历了一个布局,则返回true。

额外:获得静态定义的测量

如果只是获得静态定义的高度/宽度就足够了,你可以这样做:

  • View.getMeasuredWidth()
  • View.getMeasuredHeigth()

但请记住,这可能与绘制后的实际宽度/高度不同。 javadoc完美地描述了这个区别:

视图的大小用宽度和高度来表示。 一个视图实际上拥有两对宽度和高度值。

第一对称为测量宽度和测量高度。 这些维度定义了视图想要在其父代中有多大(请参阅布局了解更多详细信息。)可以通过调用getMeasuredWidth()和getMeasuredHeight()来获得测量的维度。

第二对简单地称为宽度和高度,或者有时绘制宽度和绘图高度。 这些尺寸定义了屏幕上的视图的实际尺寸,在绘制时间和布局之后。 这些值可能但不一定与测量的宽度和高度不同。 宽度和高度可以通过调用getWidth()和getHeight()来获得。

我们可以用

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

我用这个解决scheme,我认为比onWindowFocusChanged()更好。 如果您打开一个DialogFragment,然后旋转手机,onWindowFocusChanged将仅在用户closures对话框时被调用):

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

编辑:因为removeGlobalOnLayoutListener已被弃用,你现在应该做:

 @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 :) } 

正如伊恩在这个Android开发人员线程中所述 :

无论如何,交易是所有元素被构build并添加到他们的父视图之后 ,窗口内容的布局发生。 它必须是这样的,因为直到你知道一个视图包含什么组件,以及它包含什么,等等,没有明智的方法你可以布置它。

底线,如果您在构造函数中调用getWidth()等,它将返回零。 该过程是在构造函数中创build所有的视图元素,然后等待View的onSizeChanged()方法被调用 – 这就是当你第一次find真正的大小时,所以这就是当你设置GUI元素的大小。

也要注意,onSizeChanged()有时被称为零参数 – 检查这种情况,并立即返回(所以你没有得到除零计算您的布局等)。 一段时间后,它将被称为真正的价值。

如果您需要在屏幕上显示某个小部件的宽度,可以使用getMeasuredWidth()或getMeasuredHeight()。

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

我宁愿使用OnPreDrawListener()而不是addOnGlobalLayoutListener() ,因为它之前被调用过。

  view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { view.getViewTreeObserver().removeOnPreDrawListener(this); // put your code here return false; } }); 

在Android 7.1.2上进行了一些testing之后,我发现只有这个选项真的有用,其他的都返回0

  view.postDelayed({ height = view.height },100) 

我注意到的最有趣的事情是结果取决于延迟时间。 当我将delayMillis参数设置为60时, height = 0, delayMillis = 61 height已经有了值。 所以我猜delayMillis = 100应该够了。