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

当前回答

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

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

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

其他回答

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

就是这样。

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

我只是添加一个替代解决方案,覆盖你的活动的onWindowFocusChanged方法,你将能够得到getHeight()的值,getWidth()从那里。

@Override
public void onWindowFocusChanged (boolean hasFocus) {
        // the height will be set at this point
        int height = myEverySoTallView.getMeasuredHeight(); 
}

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

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

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

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.