如何检索视图的尺寸?
我有一个由 TableLayout、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
I have a view made up of TableLayout, TableRow and TextView
. I want it to look like a grid. I need to get the height and width of this grid. The methods getHeight()
and getWidth()
always return 0. This happens when I format the grid dynamically and also when I use an XML version.
How to retrieve the dimensions for a view?
Here is my test program I used in Debug to check the results:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
我相信OP早已不复存在,但如果这个答案能够帮助未来的搜索者,我想我会发布一个我找到的解决方案。我已将此代码添加到我的
onCreate()
方法中:编辑: 07/05/11 以包含注释中的代码:
首先,我得到对我的
的最终引用TextView
(在onGlobalLayout()
方法中访问)。接下来,我从TextView
获取ViewTreeObserver
,并添加一个OnGlobalLayoutListener
,覆盖onGLobalLayout
(似乎没有成为在此处调用的超类方法...)并添加我的代码,这需要知道此侦听器中视图的测量值。一切都按我的预期进行,所以我希望这能够有所帮助。I believe the OP is long gone, but in case this answer is able to help future searchers, I thought I'd post a solution that I have found. I have added this code into my
onCreate()
method:EDITED: 07/05/11 to include code from comments:
First I get a final reference to my
TextView
(to access in theonGlobalLayout()
method). Next, I get theViewTreeObserver
from myTextView
, and add anOnGlobalLayoutListener
, overridingonGLobalLayout
(there does not seem to be a superclass method to invoke here...) and adding my code which requires knowing the measurements of the view into this listener. All works as expected for me, so I hope that this is able to help.我将添加一个替代解决方案,重写您的活动的 onWindowFocusChanged 方法,您将能够从那里获取 getHeight() 和 getWidth() 的值。
I'll just add an alternative solution, override your activity's onWindowFocusChanged method and you will be able to get the values of getHeight(), getWidth() from there.
您正在尝试获取尚未绘制的元素的宽度和高度。
如果您使用调试并在某个时刻停止,您会看到您的设备屏幕仍然是空的,那是因为您的元素尚未绘制,所以您无法获取某些东西的宽度和高度,这还没有存在。
而且,我可能是错的,但是
setWidth()
并不总是受到尊重,Layout
布置它的子项并决定如何测量它们(调用child.measure( )
),所以如果设置setWidth()
,则不能保证在绘制元素后获得此宽度。您需要的是在实际绘制视图之后的某个位置使用 getMeasuredWidth() (视图的最新测量值)。
查看
Activity
生命周期以找到最佳时刻。http://developer.android.com/reference/android/app/ Activity.html#ActivityLifecycle
我相信一个好的做法是像这样使用
OnGlobalLayoutListener
:您可以将此代码直接放在
onCreate()
中,它将当视图被布局时调用。You are trying to get width and height of an elements, that weren't drawn yet.
If you use debug and stop at some point, you'll see, that your device screen is still empty, that's because your elements weren't drawn yet, so you can't get width and height of something, that doesn't yet exist.
And, I might be wrong, but
setWidth()
is not always respected,Layout
lays out it's children and decides how to measure them (callingchild.measure()
), so If you setsetWidth()
, you are not guaranteed to get this width after element will be drawn.What you need, is to use
getMeasuredWidth()
(the most recent measure of your View) somewhere after the view was actually drawn.Look into
Activity
lifecycle for finding the best moment.http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
I believe a good practice is to use
OnGlobalLayoutListener
like this:You can place this code directly in
onCreate()
, and it will be invoked when views will be laid out.像这样使用 View 的 post 方法
Use the View's post method like this
我尝试使用
onGlobalLayout()
来对TextView
进行一些自定义格式化,但正如 @George Bailey 注意到的,onGlobalLayout()
确实被调用两次:一次在初始布局路径上,第二次在修改文本后。View.onSizeChanged()
对我来说效果更好,因为如果我修改那里的文本,该方法只会被调用一次(在布局过程中)。这需要TextView
的子类化,但在 API 级别 11+视图。 addOnLayoutChangeListener()
可用于避免子类化。另一件事,为了在 View.onSizeChanged() 中获得正确的视图宽度,应将
layout_width
设置为match_parent
,而不是wrap_content
。I tried to use
onGlobalLayout()
to do some custom formatting of aTextView
, but as @George Bailey noticed,onGlobalLayout()
is indeed called twice: once on the initial layout path, and second time after modifying the text.View.onSizeChanged()
works better for me because if I modify the text there, the method is called only once (during the layout pass). This required sub-classing ofTextView
, but on API Level 11+View. addOnLayoutChangeListener()
can be used to avoid sub-classing.One more thing, in order to get correct width of the view in
View.onSizeChanged()
, thelayout_width
should be set tomatch_parent
, notwrap_content
.您是否试图在构造函数或在获得实际图片之前运行的任何其他方法中获取尺寸?
在实际测量所有组件之前,您不会获得任何尺寸(因为您的 xml 不知道您的显示尺寸、父级位置等)
尝试在 onSizeChanged() 之后获取值(尽管可以用零调用),或者只需等待您获得实际图像即可。
Are you trying to get sizes in a constructor, or any other method that is run BEFORE you get the actual picture?
You won't be getting any dimensions before all components are actually measured (since your xml doesn't know about your display size, parents positions and whatever)
Try getting values after onSizeChanged() (though it can be called with zero), or just simply waiting when you'll get an actual image.
正如 FX 提到的,您可以对要跟踪自身的视图使用
OnLayoutChangeListener
如果您只需要初始布局,则可以在回调中删除侦听器。
As F.X. mentioned, you can use an
OnLayoutChangeListener
to the view that you want to track itselfYou can remove the listener in the callback if you only want the initial layout.
我想这就是您需要查看的内容:使用视图的
onSizeChanged()
。以下是有关如何使用onSizeChanged()
动态获取布局或视图的高度和宽度的扩展代码片段http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions。 htmlI guess this is what you need to look at: use
onSizeChanged()
of your view. Here is an EXTENDED code snippet on how to useonSizeChanged()
to get your layout's or view's height and width dynamically http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.htmlViewTreeObserver
和onWindowFocusChanged()
根本没有必要。如果您将
TextView
扩展为布局和/或在其中放入一些内容并设置LayoutParams
那么您可以使用getMeasuredHeight()
和getMeasuredWidth()。
但是你必须小心使用
LinearLayouts
(也许还有其他ViewGroups
)。问题是,您可以在onWindowFocusChanged()
之后获取宽度和高度,但如果您尝试在其中添加一些视图,那么在绘制所有内容之前您无法获取该信息。我试图将多个TextViews
添加到LinearLayouts
来模仿FlowLayout
(环绕样式),因此无法使用Listeners
代码>.一旦该过程开始,它应该同步继续。因此,在这种情况下,您可能希望将宽度保留在变量中以便稍后使用,因为在将视图添加到布局期间,您可能需要它。ViewTreeObserver
andonWindowFocusChanged()
are not so necessary at all.If you inflate the
TextView
as layout and/or put some content in it and setLayoutParams
then you can usegetMeasuredHeight()
andgetMeasuredWidth()
.BUT you have to be careful with
LinearLayouts
(maybe also otherViewGroups
). The issue there is, that you can get the width and height afteronWindowFocusChanged()
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 multipleTextViews
toLinearLayouts
to mimic aFlowLayout
(wrapping style) and so couldn't useListeners
. 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.尽管建议的解决方案有效,但它可能不是适合每种情况的最佳解决方案,因为基于 ViewTreeObserver.OnGlobalLayoutListener 的文档
这意味着它会被调用很多次,并且并不总是测量视图(它已确定其高度和宽度)
另一种方法是使用 ViewTreeObserver.OnPreDrawListener ,仅当视图准备好绘制时才会调用它并具有其所有测量值。
Even though the proposed solution works, it might not be the best solution for every case because based on the documentation for
ViewTreeObserver.OnGlobalLayoutListener
which means it gets called many times and not always the view is measured (it has its height and width determined)
An alternative is to use
ViewTreeObserver.OnPreDrawListener
which gets called only when the view is ready to be drawn and has all of its measurements.高度和宽度为零,因为在您请求视图的高度和宽度时尚未创建视图。一种最简单的解决方案是,
与其他方法相比,该方法很好,因为它简短而清晰。
Height and width are zero because view has not been created by the time you are requesting it's height and width . One simplest solution is
This method is good as compared to other methods as it is short and crisp.
您应该查看 View 生命周期: http://developer.android.com/reference /android/view/View.html 通常,在您的 Activity 进入 onResume 状态之前,您不应该确定宽度和高度。
You should rather look at View lifecycle: http://developer.android.com/reference/android/view/View.html Generally you should not know width and height for sure until your activity comes to onResume state.
您可以使用在 OnResume() 中调用的广播
例如:
您无法在 OnCreate()、onStart() 甚至 onResume() 中获取视图的高度,因为 kcoppock 响应了
You can use a broadcast that is called in OnResume ()
For example:
You can not get the height of a view in OnCreate (), onStart (), or even in onResume () for the reason that kcoppock responded
简单回应:这对我来说没有问题。
看来关键是要确保 View 在 getHeight 等之前获得焦点。通过使用 hasFocus() 方法,然后按顺序使用 getHeight() 方法来完成此操作。只需要 3 行代码。
ImageButton myImageButton1 =(ImageButton)findViewById(R.id.imageButton1);
myImageButton1.hasFocus();
int myButtonHeight = myImageButton1.getHeight();
Log.d("按钮高度:", ""+myButtonHeight );//不需要
希望有帮助。
Simple Response: This worked for me with no Problem.
It seems the key is to ensure that the View has focus before you getHeight etc. Do this by using the hasFocus() method, then using getHeight() method in that order. Just 3 lines of code required.
ImageButton myImageButton1 =(ImageButton)findViewById(R.id.imageButton1);
myImageButton1.hasFocus();
int myButtonHeight = myImageButton1.getHeight();
Log.d("Button Height: ", ""+myButtonHeight );//Not required
Hope it helps.
对您的视图使用 getMeasuredWidth() 和 getMeasuredHeight() 。
开发者指南:查看
Use getMeasuredWidth() and getMeasuredHeight() for your view.
Developer guide: View
更正:
我发现上面的解决方案很糟糕。尤其是当你的手机速度很慢时。
在这里,我找到了另一个解决方案:
计算出元素的 px 值,包括边距和填充:
dp 到 px:
https://stackoverflow.com/a/6327095/1982712
或dimens.xml到px:
https://stackoverflow.com/a/16276351/1982712
sp 到 px:
https://stackoverflow.com/a/9219417/1982712(反转解决方案)
或尺寸为 px:
https://stackoverflow.com/a/16276351/1982712
就是这样。
CORRECTION:
I found out that the above solution is terrible. Especially when your phone is slow.
And here, I found another solution:
calculate out the px value of the element, including the margins and paddings:
dp to px:
https://stackoverflow.com/a/6327095/1982712
or dimens.xml to px:
https://stackoverflow.com/a/16276351/1982712
sp to px:
https://stackoverflow.com/a/9219417/1982712 (reverse the solution)
or dimens to px:
https://stackoverflow.com/a/16276351/1982712
and that's it.