我有一个由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

当前回答

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.

其他回答

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

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

而且,我可能是错的,但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()中,当视图被布局时,它将被调用。

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

你可以使用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响应

即使建议的解决方案有效,但它可能不是针对每种情况的最佳解决方案,因为根据ViewTreeObserver的文档。OnGlobalLayoutListener

当全局布局状态或视图树中视图的可见性发生变化时,将调用回调的接口定义。

这意味着它会被多次调用,并不总是测量视图(它的高度和宽度是确定的)

另一种方法是使用ViewTreeObserver。OnPreDrawListener只在视图准备好绘制并拥有所有测量值时被调用。

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

    @Override
    public void onPreDraw() {
        tv.getViewTreeObserver().removeOnPreDrawListener(this);
        // Your view will have valid height and width at this point
        tv.getHeight();
        tv.getWidth();
    }

});

更正: 我发现上面的解决方案很糟糕。尤其是当你的手机很慢的时候。 在这里,我找到了另一个解决方案: 计算出元素的px值,包括边距和边距: Dp到px: https://stackoverflow.com/a/6327095/1982712

或者dimensions .xml到px: https://stackoverflow.com/a/16276351/1982712

Sp对px: https://stackoverflow.com/a/9219417/1982712(反向解决方案)

或者尺寸到px: https://stackoverflow.com/a/16276351/1982712

就是这样。