onMeasure自定义视图说明

我试图做自定义组件。 我扩展了View类,并在onDraw覆盖方法中做了一些绘制。 为什么我需要重写onMeasure ? 如果我没有,一切看起来是正确的。 有人可以解释吗? 我应该如何写我的onMeasure方法? 我见过几个教程,但每个教程都有点不同。 有时他们最后调用super.onMeasure ,有时他们使用setMeasuredDimension并没有调用它。 区别在哪里?

毕竟我想使用几个完全相同的组件。 我将这些组件添加到了我的XML文件中,但我不知道它们应该有多大。 我想稍后设置它的位置和大小(为什么我需要在onDraw设置大小,如果在绘制onDraw时候,也是如此)在自定义组件类中。 当我需要这样做?

onMeasure()是告诉Android你想让自定义视图有多大依赖父级提供的布局约束的机会; 这也是您的自定义视图的机会,以了解这些布局约束(如果您想在match_parent情况下比wrap_content情况下的行为有所不同)。 这些约束被打包到传递给方法的MeasureSpec值中。 以下是模式值的粗略关联:

  • 完全意味着layout_widthlayout_height值被设置为一个特定的值。 你应该可以让你的观点这个大小。 当使用match_parent时,这也可以被触发,以精确地将尺寸设置为父视图(这是依赖于框架的布局)。
  • AT_MOST通常意味着layout_widthlayout_height值被设置为match_parentwrap_content ,其中需要最大尺寸(这是依赖于框架的布局),父尺寸的大小是值。 你不应该大于这个大小。
  • 通常意味着layout_widthlayout_height值被设置为wrap_content ,没有任何限制。 你可以是任何你想要的大小。 一些布局也使用这个callback来确定你想要的尺寸,然后再决定什么样的规格在第二个度量请求中再次传递给你。

onMeasure()存在的契约是setMeasuredDimension() 必须在最后调用你希望视图的大小。 这个方法被所有的框架实现所调用,包括在View的默认实现,这就是为什么调用super可以安全的,如果这符合你的用例。

当然,因为框架确实应用了一个默认的实现,所以你可能不需要重写这个方法,但是如果你不这样做,那么当视图空间小于你的内容时,在两个方向上使用wrap_content定制视图,您的视图可能根本不显示,因为框架不知道它有多大!

一般来说,如果你重写View而不是另一个已经存在的部件,那么提供一个实现可能是一个好主意,即使它很简单,就像这样:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int desiredWidth = 100; int desiredHeight = 100; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; //Measure Width if (widthMode == MeasureSpec.EXACTLY) { //Must be this size width = widthSize; } else if (widthMode == MeasureSpec.AT_MOST) { //Can't be bigger than... width = Math.min(desiredWidth, widthSize); } else { //Be whatever you want width = desiredWidth; } //Measure Height if (heightMode == MeasureSpec.EXACTLY) { //Must be this size height = heightSize; } else if (heightMode == MeasureSpec.AT_MOST) { //Can't be bigger than... height = Math.min(desiredHeight, heightSize); } else { //Be whatever you want height = desiredHeight; } //MUST CALL THIS setMeasuredDimension(width, height); } 

希望有所帮助。

实际上,你的答案并不完整,因为值也取决于包装容器。 在相对或线性布局的情况下,值的行为如下所示:

  • 完全 match_parent是父+的大小
  • AT_MOST wrap_content产生一个AT_MOST MeasureSpec
  • 从未触发过

在水平滚动视图的情况下,您的代码将工作。