Authorative方式来覆盖onMeasure()?

什么是重写onMeasure()的正确方法? 我见过各种方法。 例如, 专业Android开发使用MeasureSpec来计算维度,然后结束调用setMeasuredDimension()。 例如:

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); this.setMeasuredDimension(parentWidth/2, parentHeight); } 

另一方面,根据这篇文章 ,“正确的”方法是使用MeasureSpec,调用setMeasureDDimensions(), 然后调用setLayoutParams(),并以super.onMeasure()的调用结束。 例如:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); this.setMeasuredDimension(parentWidth/2, parentHeight); this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight)); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 

那么哪一个是正确的? 这两种方法都没有为我工作100%。

我想我真正要问的是没有人知道解释onMeasure(),布局,子视图的维度的教程?

其他解决scheme并不全面。 他们可能在某些情况下工作,是一个很好的开始,但他们可能不能保证工作。

当onMeasure被调用时,您可能有权或没有权利更改大小。 传递给您的onMeasure( widthMeasureSpecheightMeasureSpec )的值包含有关您的子视图允许执行的信息。 目前有三个值:

  1. MeasureSpec.UNSPECIFIED – 您可以MeasureSpec.UNSPECIFIED
  2. MeasureSpec.AT_MOST – 尽可能大(直到规格大小),这是你的例子中的parentWidth
  3. MeasureSpec.EXACTLY – 没有select。 家长select了。

这样做是为了让Android可以通过多次传递来为每个项目find合适的大小, 在这里可以看到更多细节。

如果你不遵守这些规则,你的方法不能保证工作。

例如,如果您想检查是否允许更改大小,则可以执行以下操作:

 final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY; boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY; 

使用这些信息,您将知道是否可以修改代码中的值。 或者如果你被要求做一些不同的事情。 一种快速简单的方法来解决你想要的大小是使用以下方法之一:

int resolveSizeAndState(int size,int measureSpec,int childMeasuredState)

int resolveSize(int size,int measureSpec)

虽然第一个仅在Honeycomb上可用,但第二个在所有版本上都可用。

注意:您可能会发现resizeWidthresizeHeight始终为false。 我发现这是如果我申请MATCH_PARENT的情况下。 我能够通过在我的父级布局上请求WRAP_CONTENT来解决这个问题,然后在请求阶段请求Integer.MAX_VALUE的大小。 这样做可以让您的父母在下次通过onMeasure时允许的最大大小。

文档是这方面的权威: http : //developer.android.com/guide/topics/ui/how-android-draws.html和http://developer.android.com/guide/topics/ui/custom -components.html

总结一下:在重写的onMeasure方法结束时,您应该调用setMeasuredDimension

调用super.onMeasure之后,您不应该调用setMeasuredDimension ,它将会删除您设置的任何内容。 在某些情况下,您可能需要先调用super.onMeasure ,然后通过调用setMeasuredDimension修改结果。

不要在onMeasure调用setLayoutParams 。 测量结束后,布局会在第二阶段发生。

如果更改onMeasure内部的视图大小,则setMeasuredDimension调用setMeasuredDimension 。 如果您在onMeasure之外更改大小,则需要调用setLayoutParams 。 例如改变文本时更改文本视图的大小。

取决于你正在使用的控制。 文档中的说明适用于某些控件(TextView,Button,…),但不适用于其他控件(LinearLayout,…)。 对我来说工作得很好的方法是一旦完成就打电话给超级。 根据下面的链接文章。

http://humptydevelopers.blogspot.in/2013/05/android-view-overriding-onmeasure.html

这里是我如何解决这个问题:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { .... setMeasuredDimension( measuredWidth, measuredHeight ); widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY ); heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

}

而且这对于ViewPager组件是必要的

我认为这取决于你父母的压倒一切。

例如,如果你扩展一个ViewGroup(就像FrameLayout),当你测量了大小,你应该像下面这样调用

 super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); 

因为你可能想要ViewGroup做rest工作(做一些东西在子视图上)

如果你扩展一个视图(如ImageView),你可以调用this.setMeasuredDimension(width, height); ,因为父类只会做你喜欢做的事情。

总之,如果你想要一些父类免费提供的function,你应该调用super.onMeasure() (通常是传递MeasureSpec.EXACTLY模式的度量指标),否则调用this.setMeasuredDimension(width, height); 足够。

我猜,setLayoutParams和重新计算测量值是一种解决方法,可以正确调整子视图的大小,因为这通常是在派生类的onMeasure中完成的。

然而,这很less工作正确(无论什么原因…),更好地调用measureChildren(当派生一个ViewGroup时)或者在必要时尝试类似的东西。

你可以把这段代码作为onMeasure()的一个例子

 public class MyLayerLayout extends RelativeLayout { public MyLayerLayout(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); int currentChildCount = getChildCount(); for (int i = 0; i < currentChildCount; i++) { View currentChild = getChildAt(i); //code to find information int widthPercent = currentChildInfo.getWidth(); int heightPercent = currentChildInfo.getHeight(); //considering we will pass height & width as percentage int myWidth = (int) Math.round(parentWidth * (widthPercent / 100.0)); int myHeight = (int) Math.round(parentHeight * (heightPercent / 100.0)); //Considering we need to set horizontal & vertical position of the view in parent AlignmentTraitValue vAlign = currentChildInfo.getVerticalLocation() != null ? currentChildlayerInfo.getVerticalLocation() : currentChildAlignmentTraitValue.TOP; AlignmentTraitValue hAlign = currentChildInfo.getHorizontalLocation() != null ? currentChildlayerInfo.getHorizontalLocation() : currentChildAlignmentTraitValue.LEFT; int topPadding = 0; int leftPadding = 0; if (vAlign.equals(currentChildAlignmentTraitValue.CENTER)) { topPadding = (parentHeight - myHeight) / 2; } else if (vAlign.equals(currentChildAlignmentTraitValue.BOTTOM)) { topPadding = parentHeight - myHeight; } if (hAlign.equals(currentChildAlignmentTraitValue.CENTER)) { leftPadding = (parentWidth - myWidth) / 2; } else if (hAlign.equals(currentChildAlignmentTraitValue.RIGHT)) { leftPadding = parentWidth - myWidth; } LayoutParams myLayoutParams = new LayoutParams(myWidth, myHeight); currentChildLayoutParams.setMargins(leftPadding, topPadding, 0, 0); currentChild.setLayoutParams(myLayoutParams); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }