2012-01-22 22 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