如何检索视图的维度?

我有一个由TableLayout, TableRow and 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
132744 次浏览

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

在所有组件实际测量之前,你不会得到任何尺寸(因为你的xml不知道你的显示大小,父节点位置等等)

尝试在onSizeChanged()之后获取值(尽管它可以用零调用),或者只是简单地等待,当你得到一个实际的图像。

为视图使用getMeasuredWidth()和getMeasuredHeight()。

开发人员指南:查看

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

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

而且,我可能是错的,但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
}
}
});

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

一般来说,你不应该知道宽度和高度,直到你的活动进入onResume状态。

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

我猜这是你需要看的:使用你的视图的onSizeChanged()。下面是一个关于如何使用onSizeChanged()动态获取布局或视图的高度和宽度的扩展代码片段

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

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

像这样使用视图的post方法

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

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

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

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

ViewTreeObserveronWindowFocusChanged()根本不是必要的。

如果你将TextView膨胀为布局和/或在其中放置一些内容并设置LayoutParams,那么你可以使用getMeasuredHeight()getMeasuredWidth()

你必须是小心LinearLayouts(也可能是其他ViewGroups)。这里的问题是,你可以在onWindowFocusChanged()之后获得宽度和高度,但如果你试图在其中添加一些视图,那么在所有内容都被绘制之前,你无法获得这些信息。我试图将多个TextViews添加到LinearLayouts以模拟FlowLayout(换行样式),因此不能使用Listeners。进程一旦启动,就应该同步地继续下去。所以在这种情况下,你可能想要把宽度保存在一个变量中以供以后使用,因为在添加视图到布局的过程中,你可能需要它。

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

或dimensions .xml到px: https://stackoverflow.com/a/16276351/1982712 < / p > p>sp to px: https://stackoverflow.com/a/9219417/1982712(反转解决方案)

或dimens to px: https://stackoverflow.com/a/16276351/1982712 < / p >

就是这样。

正如F.X.提到的,你可以对你想要跟踪的视图使用OnLayoutChangeListener

view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// Make changes
}
});

如果只需要初始布局,可以在回调中删除侦听器。

这对我来说没有问题。 似乎关键是要确保视图在getHeight等之前有焦点。通过使用hasFocus()方法来实现这一点,然后按此顺序使用getHeight()方法。只需要3行代码 < p > ImageButton myImageButton1 =(ImageButton)findViewById(R.id.imageButton1); myImageButton1.hasFocus(); < / p >

int myButtonHeight = myImageButton1.getHeight();

Log.d("Button Height: ", ""+myButtonHeight );//Not required

希望能有所帮助。

你可以使用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();
}


});

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

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

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