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( widthMeasureSpec
, heightMeasureSpec
)的值包含有关您的子视图允许执行的信息。 目前有三个值:
-
MeasureSpec.UNSPECIFIED
– 您可以MeasureSpec.UNSPECIFIED
-
MeasureSpec.AT_MOST
– 尽可能大(直到规格大小),这是你的例子中的parentWidth
。 -
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上可用,但第二个在所有版本上都可用。
注意:您可能会发现resizeWidth
或resizeHeight
始终为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); } }