2012-01-22 23 views
12

令我惊讶,我才发现,原来的drawLine和drawRect中不包括结束位置,即:画布的drawLine和drawRect不包括结束位置?

canvas.drawLine(100, 100, 100, 100, paint); 

RectF rect = new RectF(100, 100, 100, 100); 
canvas.drawRect(rect, paint); 

不会画任何东西。

我的油漆定义如下:

Paint paint = new Paint(); 
paint.setAntiAlias(false); 
paint.setStyle(Paint.Style.FILL); 
return paint; 

我试图定义我的涂料作为FILL_AND_STROKE,但它不会帮助。

Android的drawPaint()javadoc甚至没有列出stopX和stopY参数!

所以,如果我想画垂直线正好去从beginY到恩迪(含),我必须做到以下几点:

canvas.drawLine(constX, beginY, constX, endY + 1) 

注意,我没加1到终点X位置,仅限于结束Y(xstays与我想要的垂直线相同)。

我的设备是HTC SENSE。

编辑:西蒙,你是对的,而不是问一个问题我刚刚试图分享我的惊喜感,Android不会做它的文档在基本绘图这样的基本情况下所说的,并确保我在路上没有犯任何愚蠢的错误。

为了让自己更清楚:drawRect中的Javadoc说:

公共无效的drawRect(左浮动,浮动顶部浮动权,浮底,油漆涂料)

绘制使用指定的矩形的指定的油漆。该矩形将根据油漆中的样式进行填充或框定。

左 - 矩形的左侧被吸入

顶部 - 矩形的顶侧被吸入

右 - 矩形的右侧要绘制

底部 - 矩形的底侧被吸入

漆 - 用于绘制矩形

涂料

所以,写

canvas.drawRect(x1, y1, x2, y2) 

当你想到一个矩形,其角在(X1,Y1); (x1,y2); (x2,y1)和(x2,y2)。

Android说:错!他们将在(x1,y1); (x1,y2-1); (x2-1,y1)和(x2-1,y2-1)。

对于那些好奇:设置画布剪裁:

canvas.clipRect(x1, y1, x2, y2) 

然后试着画一个点:

canvas.drawPoint(x1, y1, paint); 

和你在屏幕上的一个点。

然后尝试在对面的角落:出现

canvas.drawPoint(x2, y2, paint); 

什么。在剩下的两个角落里也不会出现任何东西:

canvas.drawPoint(x1, y2, paint); 


canvas.drawPoint(x2, y2, paint); 

对你们来说仍然不奇怪?

所以得出的结论是,Android将权利底部坐标作为排他性,这意味着,例如,写作时:

canvas.clipRect(x1, y1, x2, y2) 

您将得到(x1,y1,x2-1,y2-1)的剪裁范围。 正确底部坐标或Rect/RectF对象的每个方法也是如此。

+0

这里有个问题吗?如果你想绘制一个点,然后使用:http://developer.android.com/reference/android/graphics/Canvas。html#drawPoint(float,%20float,%20android.graphics.Paint) –

+1

这不是问题,但我很高兴它在这里。保存我做试验来找出这个问题的答案:http://stackoverflow.com/questions/3063892/canvas-clipping-rect-right-bottom-edge-inclusive –

回答

5

你的问题揭示了Android的绘图API中的不一致性。你说

所以,如果我想画垂直线正好去从beginY到恩迪(含),我必须做到以下几点:

canvas.drawLine(constX, beginY, constX, endY + 1) 

请注意,我没有加1到结尾X位置,仅结束Y(xstays与我想要的垂直线相同)。

括号中的句子在我看来,了解矛盾的性质的关键是:

你也可以加1到结束X位置(!甚至开始X位置),和你会得到完全像素相同的线。这是为什么?因为从Android的“左像素在/右像素出”转换为“开始和结束像素在”概念的底层算法如下(仅针对x显示,因为y是相同的):

int left, top, right, bottom; // left/top pixel inclusive, right/bottom pixel exclusive 
int x1, y1, x2, y2;   // x1/y1 and x2/y2 pixels inclusive 

if (left == right) { 
    x1 = x2 = left; 
} else if (left < right) { 
    x1 = left; 
    x2 = right - 1; 
} else { 
    x1 = right; 
    x2 = left - 1; 
} 

这样的结果(在我看来次优)变换是线

canvas.drawLine(150, 150, 149, 160, paint); 

被精确地平行于

canvas.drawLine(150, 150, 151, 160, paint); 

我认为每个人都会期望一种反V,因为终点之间至少有一个像素(它们的距离是两个像素),起点是相同的。

但在各种设备和Android版本的测试,第一次完全垂直的线是在像素列149和150.列

BTW第二:正确的转换使用“开始和结束像素” - 的概念是:

int x1, y1, x2, y2;   // x1/y1 and x2/y2 pixels inclusive 

if (x1 <= x2) 
    ++x2; 
else 
    ++x1; 
if (y1 <= y2) 
    ++y2; 
else 
    ++y1; 
canvas.drawLine(x1, y1, x2, y2, paint); 
0

,如果你的背景是黑色的,加上一个语句paint.setColor(Color.RED); ,你也必须通过RectF rect = new RectF(100, 100, 100, 100); 所有点都是一样的,尽量RectF rect = new RectF(100, 100, 200, 200);

或线路canvas.drawLine(10, 10, 10, 10 + 15, paint);

0

你的矩形应该工作片,尝试添加一些背景,你的线现在是一个像素,最后两个参数不是长度,它的结束posision。

1

你的问题本质上是this的答案。谢谢。

其中之一,我并不感到惊讶,并不希望任何其他方式。这里的原因:

  • 它与java.awtjavax.swing和其他API,以及核心的Java方法,如String.substring(int, int)List<?>.get(int)一致。

  • 它兼容android.graphics.RectF,它不关心像素 - 你怎么能有一个像素的几分之一?

  • API是方便:

    • 对于40×30的矩形,实例Rect(0, 0, 40, 30)

    • Rect.right - Rect.left == Rect.width()

  • 的数学和几何形状更容易这样。例如,如果你想画在画布中居中的矩形:

 Rect clipBounds = canvas.getClipBounds() 
    int myRectWidth = 20; 
    int myRectHeight = 10; 
    int left = (clipBounds.width() - myRectWidth)/2; 
    int top = (clipBounds.height() - myRectHeight)/2; 
    int right = clipBounds.width() - left; // See how nice this is? 
    int bottom = clipBounds.height() - top; // This wouldn't work if bottom was inclusive! 
    canvas.drawRect(left, top, right, bottom);

API是正确的; the API documentation,不幸的是,只是缺乏细节。

(实际上,它是在the detail for the Rect.contains(int, int) method提及。这是不幸的是,谷歌让出无场变量本身所记录的门的API,但是。)

+0

这种行为是不符合java.awt。图形 - 如果你调用g.drawLine(100,100,100,100),你会得到一个单一的像素绘制。它也是一个特别愚蠢的行为,因为你不能像连接其他2D API一样绘制连接两点的线,并且要正确绘制线条,你必须使用drawLine(..) drawPoint(.. ..开始); drawPoint(..端..)。与字符串和列表的相似性无关紧要。 – Gilead

+0

@Gilead:我的错误:'java.awt.Graphics.drawRect()'需要一个宽度和高度参数,这符合我上面的观点,关于数学。对于Android来说,这样做也许更好。我们必须同意不同意与'String'和'List'的一致性是否相关;如果没有那么多的不一致,我会诚实地发现Android平台更易于使用。 –

+0

这个帮助我理解,但我想添加一些东西:top =屏幕底部和矩形底部之间的距离。底部=屏幕顶部与矩形上边缘之间的距离。 left =屏幕左边缘与矩形左边缘之间的距离。 right =屏幕右边缘与矩形右边缘之间的距离。 – AgentKnopf