我创建了一个自定义视图,其中onDraw()
被覆盖,在画布上绘制一个位图。当我在布局文件中指定我想要它wrap_content时,它仍然会填满整个屏幕。 onMeasure()
说:
measure的基类实现默认为背景大小,除非
MeasureSpec
允许更大的大小。子类应覆盖onMeasure(int,int)以提供更好的内容测量。
好酷,所以我知道我需要覆盖onMeasure()
并使用MeasureSpec
。根据{{3}}
UNSPECIFIED表示layout_width或layout_height值设置为wrap_content。你可以任意大小。
现在我遇到了我的问题,我如何在onMeasure()
测量我尚未创建的位图并测量/包装它?我知道其他Android视图必须做一些事情,因为如果设置为wrap_content,它们不会阻挡整个屏幕。提前谢谢!
答案 0 :(得分:19)
This is the order这些常用的视图方法在:
中运行1. Constructor // choose your desired size
2. onMeasure // parent will determine if your desired size is acceptable
3. onSizeChanged
4. onLayout
5. onDraw // draw your view content at the size specified by the parent
如果您的视图可以是任何尺寸,它会选择多大的尺寸?这将是您的wrap_content
尺寸,具体取决于您的自定义视图的内容。例子:
dp
to px
size。)如果您想要的大小使用繁重的计算,那么在构造函数中执行此操作。否则,您只需在onMeasure
中分配即可。 (onMeasure
,onLayout
和onDraw
可能会被多次调用,这就是为什么在这里做繁重的工作并不好。)
onMeasure
是孩子告诉父母有多大的地方,父母决定这是否可以接受。这种方法经常被调用几次,每次都传递不同的大小要求,看看是否可以达到一些妥协。但最终,孩子需要尊重父母的身材要求。
当我需要复习如何设置我的onMeasure
时,我总是回到this answer:
@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);
}
在上面的示例中,所需的宽度和高度仅设置为某些默认值。您可以事先计算它们,并使用类成员变量在此处设置它们。
在onMeasure
之后,您的视图大小已知。这个大小可能是您要求的,也可能不是您所要求的,但这是您现在必须使用的。使用该尺寸在onDraw
中的视图上绘制内容。
invalidate()
。这将导致再次调用onDraw
(但不是所有其他先前的方法)。requestLayout()
。这将从onMeasure
开始重新测量和绘制的过程。通常是combined with a call to invalidate()
。invalidate()
)。这看起来有点浪费,因为你要求整个视图层次结构连续布局两次。答案 1 :(得分:3)
如果在onMeasure调用之前无法测量位图,则可以返回大小为零,直到加载位图。加载后,使父ViewGroup无效以强制执行另一个度量(不记得View本身上的invalidate()是否会强制onMeasure)。