如何检索视图的尺寸?

207 layout lifecycle android android-widget measure

我有一个观点TableLayout, TableRow and TextView.我希望它看起来像一个网格.我需要得到这个网格的高度和宽度.这些方法getHeight()getWidth()总是返回0.这发生在我和动态也格式化网格时我使用XML版本.

如何检索视图的尺寸?


这是我在Debug中用来检查结果的测试程序:

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
Run Code Online (Sandbox Code Playgroud)

kco*_*ock 415

我相信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);
        }
    }

});
Run Code Online (Sandbox Code Playgroud)

首先,我得到了对我的最终引用TextView(要在onGlobalLayout()方法中访问).接下来,我ViewTreeObserver从my 获取TextView,并添加一个OnGlobalLayoutListener覆盖onGLobalLayout(似乎没有超级类方法在这里调用...)并添加我的代码,这需要知道视图的测量值到这个监听器.一切都按预期的方式进行,所以我希望能够提供帮助.

  • @George Bailey:我最近看到别人发布的一件事(我没有亲自测试,所以YMMV)来克服多次调用(在onGlobalLayout()内):`tv.getViewTreeObserver().removeGlobalOnLayoutListener(this) ;`这种方式应该在第一次发生后删除监听器. (23认同)
  • 问题很老,但使用`addOnLayoutChangeListener`也可以!:) (7认同)
  • 另请注意,自API 16起,您需要:if(android.os.Build.VERSION.SDK_INT> = 16){view.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else {view.getViewTreeObserver().removeGlobalOnLayoutListener(this); } (7认同)
  • 我也想帮忙.您可能需要执行以下操作:mView.getViewTreeObserver().removeGlobalOnLayoutListener(globalLayoutListener); 如果您只想调整一次视图大小.希望这有帮助 (3认同)
  • 由于不推荐使用removeGlobalOnLayoutListener,它仍会在Eclipse中发出警告.这是正常的吗?随着时间的推移,已弃用的代码警告会泛滥成灾...... (2认同)
  • @Jonny请记住,这个答案是在2年前弃用之前发布的.:) (2认同)

Jus*_*yul 82

我将添加一个替代解决方案,覆盖您的活动的onWindowFocusChanged方法,您将能够从那里获取getHeight(),getWidth()的值.

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

  • 对于必须使用`ViewTreeObserver`的Fragments,这不起作用. (6认同)
  • 引用文档,"这是用户可以看到此活动的最佳指标." (3认同)

Ale*_*lov 19

您正在尝试获取尚未绘制的元素的宽度和高度.

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

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

你需要的是getMeasuredWidth()在实际绘制视图后的某个地方使用(最近的视图测量).

查看Activity生命周期以找到最佳时刻.

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
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

您可以直接放置此代码onCreate(),并在布局视图时调用它.


Bor*_*sev 15

像这样使用View的post方法

post(new Runnable() {   
    @Override
    public void run() {
        Log.d(TAG, "width " + MyView.this.getMeasuredWidth());
        }
    });
Run Code Online (Sandbox Code Playgroud)


Y2i*_*Y2i 7

我试图用来onGlobalLayout()做一些自定义格式化TextView,但正如@George Bailey注意到的那样,onGlobalLayout()确实被调用了两次:一次是在初始布局路径上,第二次是在修改文本之后.

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

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


Ale*_*lov 2

您是否试图在构造函数或在获得实际图片之前运行的任何其他方法中获取尺寸?

在实际测量所有组件之前,您不会获得任何尺寸(因为您的 xml 不知道您的显示尺寸、父位置等)

尝试在 onSizeChanged() 之后获取值(尽管可以用零调用),或者只是等待获取实际图像。