Android 自定义视图如何计算 onMeasure 来填满父布局

5
我正在尝试绘制一个自定义视图,除了右侧部分被截断之外,一切都渲染正常。我想让视图填满父元素,并仅使用所需高度(即我正在绘制的位图的高度)。当我从活动的xml布局中删除填充时,自定义视图就可以正常渲染了。因此,我没有考虑父元素的填充来计算onMeasure。
请问是否有人可以查看一下这段代码并描述我错在哪里以及如何解决问题?谢谢。
编辑后包括@nicko的答案和更多详细信息:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
    int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);

    ViewParent parent = getParent();
    int leftPadding = 0;
    int rightPadding = 0;

    if (parent instanceof ViewGroup) {
        leftPadding = ((ViewGroup) parent).getPaddingLeft();
        rightPadding = ((ViewGroup) parent).getPaddingRight();
    }
    float wanabeHeight = calendar.getHeight();
    float wanabeWidth = parentWidth - leftPadding - rightPadding;

    int height = 0;
    //Determine Height
    switch(heightMode){
        case MeasureSpec.EXACTLY: height = parentHeight;
            break;
        case MeasureSpec.AT_MOST:
            height = Math.min((int)wanabeHeight, parentHeight);
            break;
        case MeasureSpec.UNSPECIFIED:
        default:
            height = (int)wanabeHeight;
            break;
    }
    setMeasuredDimension((int)wanabeWidth, height);
}


@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    calendarX = left;
    personX = (int)((right - left) * 0.5);
    checkX = right - check.getWidth() - getPaddingRight();
    lineY = (int)((bottom - top) * 0.5);
    bitmapY = (int)(((bottom - top) * 0.5) - (calendar.getHeight() * 0.5));
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(calendar, calendarX, bitmapY, paint);
    canvas.drawBitmap(person, personX, bitmapY, paint);
    canvas.drawBitmap(check, checkX, bitmapY, paint);

    canvas.drawLine((calendarX + calendar.getWidth() + PADDING), lineY, personX - PADDING, lineY, linePaint);
    canvas.drawLine((personX + person.getWidth() + PADDING), lineY, checkX - PADDING, lineY, linePaint);
}
2个回答

2
onDraw方法中,所有的绘制都是相对于画布的 - 但是你似乎根据onLayout接收到的与屏幕相关的视图位置来进行绘制。

因此,对于右侧的图像,你实际上需要按如下方式计算X位置:

checkX = right - left - check.getWidth();

如果父元素有任何内边距,您可能会发现左侧图像会缩进一点,因此请尝试将其定位为0:

calendarX = 0;

1
您可以按以下方式获取父元素的内边距:

ViewParent parent = getParent();
int topPadding = 0;
int bottomPadding = 0;

if (parent instanceof ViewGroup) {
    topPadding = ((ViewGroup) parent).getPaddingTop();
    bottomPadding = ((ViewGroup) parent).getPaddingBottom();
}

并使用它:

parentHeight -= topPadding - bottomPadding;
int height = 0;

//Determine Height
switch(heightMode){
    case MeasureSpec.EXACTLY: 
        height = parentHeight;
        break;
    case MeasureSpec.AT_MOST:
        height = Math.min((int)wanabeHeight, parentHeight);
        break;
    case MeasureSpec.UNSPECIFIED:
    default:
        height = (int)wanabeHeight; 
        break;
}

不需要进行“parent != null”的检查,因为这可以通过instanceof运算符轻松地管理。 - Ameer Moaaviah
嗨,我尝试了这个方法,但是正确的位图(check)仍然被裁剪了。我修改了你的答案,调整了父宽度而不是高度(因为右侧被裁剪了)。我在onLayout()中计算checkX,在onDraw()中绘制位图“check”。 - serenskye
是的,您可以使用相同的方法获取左右填充,并像我的示例代码中使用高度一样使用它们。 - Niko
这个解决方案对我来说没有解决问题。 - serenskye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接