it-swarm.cn

覆盖onMeasure()的权威方式?

覆盖onMeasure()的正确方法是什么?我见过各种方法。例如,Professional Android Development使用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);
}

那么哪种方式正确?这两种方法都没有对我有效。

我想我真正想要的是有没有人知道一个解释onMeasure(),布局,子视图尺寸等的教程?

87
U Avalos

其他解决方案并不全面。它们可能在某些情况下起作用,并且是一个很好的起点,但它们可能无法保证工作。

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

  1. MeasureSpec.UNSPECIFIED - 你可以像你想的那样大
  2. MeasureSpec.AT_MOST - 尽可能大(最大规格尺寸),在您的示例中为parentWidth
  3. MeasureSpec.EXACTLY - 别无选择。家长选择了。

这样做是为了让Android可以进行多次传递以找到每个项目的正确大小,请参阅 here 了解更多详情。

如果您不遵守这些规则,则无法保证您的方法有效。

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

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时允许的最大大小。

66
Grimmace

文档是此事的权威: http://developer.Android.com/guide/topics/ui/how-Android-draws.htmlhttp://developer.Android.com/guide /topics/ui/custom-components.html

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

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

不要在setLayoutParams中调用onMeasure。布局在测量后的第二遍中发生。

38
satur9nine

这是我如何解决问题:

@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组件也是必需的

0
Yuli Reiri

我认为这取决于父母你最重要的是什么。

例如,如果您正在扩展ViewGroup(如FrameLayout),那么在测量大小时,您应该调用如下

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

因为你可能想让ViewGroup做休息工作(在子视图上做一些事情)

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

在Word中,如果你想要一些你的父类免费提供的功能,你应该调用super.onMeasure()(通常通过MeasureSpec.EXACTLY模式测量规范),否则调用this.setMeasuredDimension(width, height);就足够了。

0
Yon

取决于您正在使用的控件。文档中的说明适用于某些控件(TextView,Button,...),但不适用于其他控件(LinearLayout,...)。对我来说非常有效的方法是在完成后给超级电话打电话。基于以下链接中的文章。

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

0
Aviral

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

0
Kyle O.