onMeasure():wrap_content,我怎么知道要包装的大小?

Sim*_*all 14 android view custom-component

我已经创建了一个自定义视图,onDraw()覆盖了画布上的位图.当我在布局文件中指定我想要它wrap_content时,它仍然会填满整个屏幕.onMeasure()这样说:

measure的基类实现默认为背景大小,除非允许更大的大小MeasureSpec.子类应覆盖onMeasure(int,int)以提供更好的内容测量.

好酷,所以我知道我需要覆盖onMeasure()和使用MeasureSpec.根据这个答案

unex表示layout_width或layout_height值设置为wrap_content.你可以任意大小.

现在我遇到了我的问题,我如何onMeasure()测量我尚未创建的位图并测量/包装它?我知道其他Android视图必须做一些事情,因为如果设置为wrap_content,它们不会阻挡整个屏幕.提前致谢!

Sur*_*gch 24

这是运行这些常用视图方法的顺序:

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
Run Code Online (Sandbox Code Playgroud)

选择所需的尺寸

如果您的视图可以是任何尺寸,它会选择多大的尺寸?这将是您的wrap_content尺寸,将取决于您的自定义视图的内容.例子:

  • 如果您的自定义视图是图像,那么您所需的大小可能是位图的像素尺寸加上任何填充.(在选择尺寸和绘制内容时,您有责任将填充计算到计算中.)
  • 如果您自定义视图是模拟时钟,那么所需的大小可能是一些它看起来很好的默认大小.(你总是可以得到的dp,以px大小的设备.)

如果您想要的大小使用繁重的计算,那么在构造函数中执行此操作.否则,您可以将其分配onMeasure.(onMeasure,onLayout并且onDraw可能会多次调用,这就是为什么在这里做繁重工作不好的原因.)

谈判最终规模

onMeasure是孩子告诉父母有多大的地方,父母决定这是否可以接受.这种方法经常被调用几次,每次都传递不同的大小要求,看看是否可以达到一些妥协.但最后,孩子需要尊重父母的身材要求.

当我需要复习如何设置我的时候,我总是回到这个答案onMeasure:

@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);
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,所需的宽度和高度仅设置为某些默认值.您可以事先计算它们并使用类成员变量在此处设置它们.

使用所选尺寸

之后onMeasure,您的视图大小已知.这个大小可能是您要求的,也可能不是您所要求的,但这是您现在必须使用的.使用该大小在视图中绘制内容onDraw.

笔记

  • 每当您对视图进行更改而影响外观但不影响大小时,请致电invalidate().这将导致onDraw再次调用(但不是所有其他先前的方法).
  • 如果您对视图进行了更改会影响大小,请致电requestLayout().这将重新开始测量和绘图的过程onMeasure.它通常与呼叫相结合invalidate().
  • 如果由于某种原因你事先无法确定合适的所需尺寸,那么我想你可以像@nmw建议那样做,只要求零宽度,零高度.然后invalidate()在加载完所有内容后请求布局(不仅仅是).这看起来有点浪费,因为您要求整个视图层次结构连续布局两次.


nmw*_*nmw 4

如果您无法在 onMeasure 调用之前测量位图,则可以返回大小为零,直到加载位图。加载后,使父 ViewGroup 无效以强制执行另一个测量(不记得 View 本身上的 invalidate() 是否会强制执行 onMeasure)。


归档时间:

查看次数:

11050 次

最近记录:

8 年,8 月 前