我有一个由tableelayout, TableRow和TextView组成的视图。我想让它看起来像一个网格。我需要得到这个网格的高度和宽度。方法getHeight()和getWidth()总是返回0。当我动态格式化网格和使用XML版本时,就会发生这种情况。

如何检索视图的维度?


下面是我在调试中用来检查结果的测试程序:

import android.app.Activity;
import android.os.Bundle;
import android.widget.TableLayout;
import android.widget.TextView;

public class appwig extends Activity {  
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"
      int vh = 0;   
      int vw = 0;

      //Test-1 used the xml layout (which is displayed on the screen):
      TableLayout tl = (TableLayout) findViewById(R.id.board);  
      tl = (TableLayout) findViewById(R.id.board);
      vh = tl.getHeight();     //<- getHeight returned 0, Why?  
      vw = tl.getWidth();     //<- getWidth returned 0, Why?   

      //Test-2 used a simple dynamically generated view:        
      TextView tv = new TextView(this);
      tv.setHeight(20);
      tv.setWidth(20);
      vh = tv.getHeight();    //<- getHeight returned 0, Why?       
      vw = tv.getWidth();    //<- getWidth returned 0, Why?

    } //eof method
} //eof class

当前回答

我相信OP早就消失了,但如果这个答案能够帮助未来的搜索者,我想我应该发布一个我发现的解决方案。我已经在onCreate()方法中添加了以下代码:

编辑:07/05/11以包括来自注释的代码:

final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        LayerDrawable ld = (LayerDrawable)tv.getBackground();
        ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
        ViewTreeObserver obs = tv.getViewTreeObserver();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
        } else {
            obs.removeGlobalOnLayoutListener(this);
        }
    }

});

首先,我得到一个最终引用我的TextView(访问在onGlobalLayout()方法)。接下来,我从我的TextView获得ViewTreeObserver,并添加一个OnGlobalLayoutListener,覆盖onGLobalLayout(似乎没有一个超类方法调用这里…)并添加我的代码,这需要知道视图的测量到这个侦听器。一切都如我所料,所以我希望这是能够帮助。

其他回答

你应该查看视图生命周期:http://developer.android.com/reference/android/view/View.html通常你不应该知道宽度和高度,直到你的活动进入onResume状态。

高度和宽度为零,因为在你请求它的高度和宽度时,视图还没有被创建。最简单的解决方法是

view.post(new Runnable() {
    @Override
    public void run() {
        view.getHeight(); //height is ready
        view.getWidth(); //width is ready
    }
});

与其他方法相比,这种方法是很好的,因为它是短而脆。

你试图得到一个元素的宽度和高度,这些元素还没有被画出来。

如果你使用调试并在某个点停止,你会看到,你的设备屏幕仍然是空的,那是因为你的元素还没有绘制,所以你不能得到宽度和高度,那还不存在。

而且,我可能是错的,但setWidth()并不总是尊重,布局布局它的孩子,并决定如何测量他们(调用child.measure()),所以如果你设置setWidth(),你不保证得到这个宽度后的元素将被绘制。

您需要的是在视图实际绘制之后的某个位置使用getMeasuredWidth()(视图的最新测量值)。

查看活动生命周期以找到最佳时刻。

http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

我相信一个好的做法是这样使用OnGlobalLayoutListener:

yourView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (!mMeasured) {
                // Here your view is already layed out and measured for the first time
                mMeasured = true; // Some optional flag to mark, that we already got the sizes
            }
        }
    });

您可以将此代码直接放在onCreate()中,当视图被布局时,它将被调用。

ViewTreeObserver和onWindowFocusChanged()根本不是必要的。

如果你膨胀的TextView作为布局和/或放一些内容在它和设置LayoutParams然后你可以使用getMeasuredHeight()和getMeasuredWidth()。

BUT you have to be careful with LinearLayouts (maybe also other ViewGroups). The issue there is, that you can get the width and height after onWindowFocusChanged() but if you try to add some views in it, then you can't get that information until everything have been drawn. I was trying to add multiple TextViews to LinearLayouts to mimic a FlowLayout (wrapping style) and so couldn't use Listeners. Once the process is started, it should continue synchronously. So in such case, you might want to keep the width in a variable to use it later, as during adding views to layout, you might need it.

你可以使用OnResume()中调用的广播

例如:

int vh = 0;   
int vw = 0;

public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"

      registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                TableLayout tl = (TableLayout) findViewById(R.id.board);  
                tl = (TableLayout) findViewById(R.id.board);
                vh = tl.getHeight();       
                vw = tl.getWidth();               
            }
      }, new IntentFilter("Test"));
}

protected void onResume() {
        super.onResume();

        Intent it = new Intent("Test");
        sendBroadcast(it);

}

你不能在OnCreate (), onStart(),甚至在onResume()中获得视图的高度,原因是kcoppock响应