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

什么时候

View.onMeasure(int widthMeasureSpec, int heightMeasureSpec) 

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

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

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

  • 通过调整布局参数拖动旋转的视图
  • 在视图中运行RunUnUiThread
  • android如何在布局开始时添加视图?
  • 将位图的大小调整为固定值,但不更改宽高比
  • 当paint设置为Stroke时,Android Canvas.drawTextOnPath看起来不正确
  • 背景上的不透明度视图中的可绘制图像(使用XML布局)
  • 有没有办法在Android中偏移中心的视图?
  • Android中的“preconcat”矩阵是什么意思?
  • 当父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源代码