Java 什么时候调用 View.onMeasure()?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6631105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When is View.onMeasure() called?
提问by GregNash
When is
什么时候
View.onMeasure(int widthMeasureSpec, int heightMeasureSpec)
called? I have an Activitythat needs to perform an action after onMeasurehas been called.
叫?我有一个Activity需要在调用onMeasure后执行操作。
My question is the same as the unanswered question posted here. The Viewdocumentation states that onMeasureis called when requestLayout()is called, which is apparently called by a view on itself when it believes that is can no longer fit within its current bounds.
我的问题与此处发布的未回答问题相同。在查看文档指出onMeasure当被称为requestLayout()被调用时,它显然是对自身视图调用时它认为是不能再目前的范围内配合。
However, this doesn't tell me when my activity can assume that my Viewhas been measured. I've used this codeto extend ImageViewto form TouchImageView. It was suggested herethat I should use the onMeasuremethod to scale my image. I wish to update the value of a TextViewafter the ImageViewhas been measured in order to display the percentage by which the image has been scaled.
但是,这并没有告诉我我的活动何时可以假设我的视图已被测量。我已使用此代码扩展ImageView以形成 TouchImageView。这里建议我应该使用onMeasure方法来缩放我的图像。我希望在测量ImageView后更新TextView的值,以显示图像缩放的百分比。
采纳答案by Matthieu
onMeasure is called when the parent View needs to calculate the layout. Typically, onMeasure may be called several times depending on the different children present and their layout parameters.
onMeasure 在父 View 需要计算布局时调用。通常,根据存在的不同子项及其布局参数,可能会多次调用 onMeasure。
The best way to do something when onMeasureis called is (I think) to create your own control, extend the ImageViewand override onMeasure (just call super.onMeasure and do whatever else you would like to do).
调用onMeasure时做某事的最佳方法是(我认为)创建自己的控件,扩展ImageView并覆盖 onMeasure(只需调用 super.onMeasure 并执行您想做的任何其他操作)。
If you do that, just keep in mind that on Measure may be called several times with different parameters, so whatever is measured may not be the final width and height of what will be actually displayed.
如果这样做,请记住,可能会使用不同的参数多次调用 Measure ,因此所测量的内容可能不是实际显示内容的最终宽度和高度。
回答by Suragch
You can get your custom view's measurements in onSizeChanged
.
您可以在onSizeChanged
.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// use the provided width and height for whatever you need
}
Explanation
解释
When a view is created, this is the order in which the following methods are called:
创建视图时,这是调用以下方法的顺序:
- Constructor
CustomView(Context context)
(if created programmatically)CustomView(Context context, AttributeSet attrs)
(if created from xml)
onFinishInflate
(assuming you used the xml constructor)onAttachedToWindow
onMeasure
onSizeChanged
onLayout
onDraw
- 构造函数
CustomView(Context context)
(如果以编程方式创建)CustomView(Context context, AttributeSet attrs)
(如果从 xml 创建)
onFinishInflate
(假设您使用了 xml 构造函数)onAttachedToWindow
onMeasure
onSizeChanged
onLayout
onDraw
The earliest you can get the view's measurements is in onMeasure
. Before that the width and height are 0
. However, the only thing you should be doing in onMeasure
is determining the size of the view. This method gets called several times while the view is telling the parent how big it wants to be but the parent is determining the actual final size. (See this answerfor how onMeasure
is meant to be used.)
您最早可以获得视图的测量值是在onMeasure
. 在此之前,宽度和高度是0
. 但是,您唯一应该做的onMeasure
就是确定视图的大小。当视图告诉父级它想要多大但父级正在确定实际的最终大小时,此方法会被多次调用。(有关如何使用的信息,请参阅此答案onMeasure
。)
If you want to actually use the measured size for anything, the earliest place to do that is in onSizeChanged
. It gets called whenever the view is created because the size is changing from 0
to whatever the size is.
如果您想将测量的尺寸实际用于任何东西,最早的地方是在onSizeChanged
. 每当创建视图时都会调用它,因为大小正在更改0
为任何大小。
You could also use onLayout
, though as I understand it, onLayout
is for customizing how any children of your custom view are laid out. It also might get called more often than onSizeChanged
, for example, if you call requestLayout()
when the size hasn't actually changed.
您也可以使用onLayout
,但据我所知,onLayout
是用于自定义自定义视图的任何子项的布局方式。它也可能比 更频繁地被调用onSizeChanged
,例如,如果您requestLayout()
在大小实际上没有改变时调用。
You can also access the size in onDraw
with getMeasuredWidth()
and getMeasuredHeight()
. However, if you are using them to do any heavy calculations, it is better to do that beforehand. Generally speaking, try to keep as much out of onDraw
as possible since it may be called multiple times. (It gets called whenever invalidate()
gets called.)
您还可以onDraw
使用getMeasuredWidth()
和访问大小getMeasuredHeight()
。但是,如果您使用它们进行任何繁重的计算,最好事先进行。一般来说,尽量避免,onDraw
因为它可能会被多次调用。(每当invalidate()
被调用时它就会被调用。)
See for yourself
你自己看
If you don't believe me, you can see the order of events as they are called in the custom view below. Here is the output:
如果您不相信我,您可以在下面的自定义视图中看到事件的顺序。这是输出:
XML constructor called, measured size: (0, 0)
onFinishInflate called, measured size: (0, 0)
onAttachedToWindow called, measured size: (0, 0)
onMeasure called, measured size: (350, 1859)
onMeasure called, measured size: (350, 350)
onMeasure called, measured size: (350, 2112)
onMeasure called, measured size: (350, 350)
onSizeChanged called, measured size: (350, 350)
onLayout called, measured size: (350, 350)
onDraw called, measured size: (350, 350)
activity_main.xml
活动_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.viewlifecycle.CustomView
android:id="@+id/customView"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent"/>
</RelativeLayout>
CustomView.java
自定义视图.java
public class CustomView extends View {
private void printLogInfo(String methodName) {
Log.i("TAG", methodName + " called, measured size: (" + getMeasuredWidth() + ", " + getMeasuredHeight() + ")");
}
// constructors
public CustomView(Context context) {
super(context);
printLogInfo("Programmatic constructor");
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
printLogInfo("XML constructor");
}
// lifecycle methods
@Override
protected void onFinishInflate() {
super.onFinishInflate();
printLogInfo("onFinishInflate");
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
printLogInfo("onAttachedToWindow");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
printLogInfo("onMeasure");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
printLogInfo("onSizeChanged");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
printLogInfo("onLayout");
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
printLogInfo("onDraw");
}
}