我有一个由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的文档。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();
    }

});

其他回答

我相信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(似乎没有一个超类方法调用这里…)并添加我的代码,这需要知道视图的测量到这个侦听器。一切都如我所料,所以我希望这是能够帮助。

我试图使用onGlobalLayout()做一些自定义格式的TextView,但@乔治贝利注意到,onGlobalLayout()确实被调用两次:一次在初始布局路径上,第二次修改文本后。

View.onSizeChanged()对我来说工作得更好,因为如果我在那里修改文本,该方法只被调用一次(在布局传递期间)。这需要子类化TextView,但在API级别11+视图。addOnLayoutChangeListener()可以用来避免子类化。

还有一件事,为了在view . onsizechanged()中获得正确的视图宽度,layout_width应该设置为match_parent,而不是wrap_content。

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

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.

更正: 我发现上面的解决方案很糟糕。尤其是当你的手机很慢的时候。 在这里,我找到了另一个解决方案: 计算出元素的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

就是这样。