什么时候调用View.onMeasure()?

什么时候

View.onMeasure(int widthMeasureSpec, int heightMeasureSpec) 

叫什么名字? 我有一个Activity ,需要在调用onMeasure后执行一个动作。

我的问题与此处发布的未回答的问题相同。 View文档声明在调用requestLayout()时调用onMeasure ,当它认为它不再适合其当前边界时,它显然由一个视图调用。

但是,这并没有告诉我何时我的活动可以假设我的视图已被测量。 我已经使用此代码将ImageView扩展为TouchImageView。 这里建议我应该使用onMeasure方法来缩放我的图像。 我希望在测量ImageView后更新TextView的值,以显示图像缩放的百分比。

当父View需要计算布局时调用onMeasure。 通常,onMeasure可能会被调用多次,具体取决于存在的不同子项及其布局参数。

调用onMeasure时执行某些操作的最佳方法是(我认为)创建自己的控件,扩展ImageView并覆盖onMeasure(只需调用super.onMeasure并执行其他任何您想要执行的操作)。

如果你这样做,请记住,在测量上可能会使用不同的参数多次调用,因此测量的内容可能不是实际显示的最终宽度和高度。

您可以在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 } 

说明

创建视图时,这是调用以下方法的顺序:

  1. 构造函数
    • CustomView(Context context) (如果以编程方式创建)
    • CustomView(Context context, AttributeSet attrs) (如果从xml创建)
  2. onFinishInflate (假设你使用了xml构造函数)
  3. onAttachedToWindow
  4. onMeasure
  5. onSizeChanged
  6. onLayout
  7. onDraw

您最早可以获得视图的测量值在onMeasure 。 在此之前,宽度和高度为0 。 但是,你应该在onMeasure上做的唯一事情就是确定视图的大小。 这个方法被调用多次,而视图告诉父母它想要多大但父母确定实际的最终大小。 (有关如何使用onMeasure请参阅此答案 。)

如果你想实际使用测量的大小,那么最早的地方是onSizeChanged 。 每当创建视图时都会调用它,因为大小从0变为任何大小。

您也可以使用onLayout ,但据我了解, onLayout用于自定义自定义视图的任何子项的布局方式。 它也可能比onSizeChanged更频繁地调用,例如,如果在实际没有更改大小时调用requestLayout()

您还可以使用getMeasuredWidth()getMeasuredHeight()访问onDraw的大小。 但是,如果您使用它们进行任何繁重的计算,最好事先做好。 一般来说,尝试尽可能多地保留onDraw ,因为它可能被多次调用。 (无论何时调用invalidate()都会调用它。)

你自己看

如果您不相信我,您可以在下面的自定义视图中查看事件的顺序。 这是输出:

 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中

 < ?xml version="1.0" encoding="utf-8"?>    

CustomView.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"); } } 

进一步阅读

  • View文档
  • Android如何绘制视图
  • Android View生命周期
  • View源代码