2013-10-31 93 views
-2

example path如何繪製帶邊框的路徑?

我想畫一條類似於圖像的路徑。它有兩個黑色邊框,裏面是白色而不是透明的。如何實現它?特別是關節位置。

+0

drawPath使用不同顏色的兩次snd中風寬度 – pskink

+0

如果您嘗試過,您會發現它不起作用。關節不會有黑線。 – Acheese

+0

好的,所以你不能用一個路徑來完成它,你必須繪製兩個路徑段,其中一個透視另一個 – pskink

回答

18

要獲得所需的結果,您必須繪製部分路徑。

您將繪製零件兩次,其中兩個不同的Paint對象僅在筆畫寬度和顏色方面有所不同。繪製每個部分後,路徑將被重置。該代碼註釋應該解釋其餘部分:

public class SView extends View { 

    Path path; 
    Paint paint, paintWhite; 
    RectF rf, rf2, rf3; 

    public SView(Context context) { 
     super(context); 

     path = new Path(); 

     // 'paint' has a wider stroke-width 
     // compared to 'paintWhite' and 
     // thus becomes the border paint 
     paint = new Paint(); 
     paint.setColor(Color.BLUE); 
     paint.setAntiAlias(true); 
     paint.setStrokeWidth(15); 
     paint.setStyle(Style.STROKE); 

     // 'paintWhite' colors the inner path 
     paintWhite = new Paint(); 
     paintWhite.setColor(Color.WHITE); 
     paintWhite.setAntiAlias(true); 
     paintWhite.setStrokeWidth(12); 
     paintWhite.setStyle(Style.STROKE); 

     // For this example, we'll draw three 
     // arcs bound by the following RectF 
     // objects 
     rf = new RectF(200, 200, 500, 500); 
     rf2 = new RectF(200, 200, 400, 500); 
     rf3 = new RectF(100, 200, 400, 500);      
    } 

    @Override 
    protected void onDraw(Canvas canvas) {   

     // First arc bound by 'rf' 
     path.arcTo(rf, 0, 180); 

     // Draw 'path' using 'paint' 
     // and then, again using 'paintWhite'  
     canvas.drawPath(path, paint); 
     canvas.drawPath(path, paintWhite); 

     // Reset 'path' so as to clear 
     // history 
     path.reset(); 

     // Repeat with the rest of arcs 
     path.arcTo(rf2, 180, 180);  
     canvas.drawPath(path, paint); 
     canvas.drawPath(path, paintWhite);  
     path.reset();   

     path.arcTo(rf3, 0, 180);    
     canvas.drawPath(path, paint); 
     canvas.drawPath(path, paintWhite); 

    }  
} 

輸出:

enter image description here

注:重疊圓弧被RectF rf3約束,並最後繪製。

由於我們正在繪製white部分以及borders,因此您將不會結束四路交叉。這些部分將以flyover種類的時尚重疊:按照它們的繪製順序。

爲了提升性能(我想),您可以在重置路徑之前檢查路徑的下一部分是否與之前的路徑相交。如果下一個零件相交,則重置並用兩個Paint對象繪製零件。如果沒有,只需將該部件追加到路徑中並等待直到下一個路口繪製它。您當然需要維護繪製的零件歷史記錄(在上面的例子中,歷史將包含界限:'RectF'對象)。但是,我不是100%確定這是否比反覆重新設置路徑然後繪製零件更好。

1

您可以嘗試使用兩個不同的Paint對象繪製相同的路徑。第一個Paint對象將具有您想要的邊框顏色和較大的筆觸寬度。第二個Paint將具有較小的筆觸寬度,並設置PorterDuff.Mode.CLEAR

linePaint = new Paint(); 
linePaint.setAntiAlias(true); 
linePaint.setColor(Color.YELLOW); 
linePaint.setStrokeWidth(6); 
linePaint.setStyle(Paint.Style.STROKE); 

clearPaint = new Paint(); 
clearPaint.setAntiAlias(true); 
clearPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); 
clearPaint.setStyle(Paint.Style.STROKE); 
clearPaint.setStrokeWidth(3); 

然後在您的onDraw()方法,通過使用上述兩種油漆兩次繪製相同的路徑。

canvas.drawPath(path, linePaint); 
canvas.drawPath(path, clearPaint); 

這在性能方面可能效率不高,但這是我能想到的最簡單的方法。

編輯:沒有測試過這個徹底我自己,所以請讓我知道是否有任何問題。

更新:經過測試,我發現PorterDuff.Mode.CLEAR將清除畫布'支持位圖中存在的整個像素信息。因此,人們通常會用這樣的事情結束了:

Path filled with black

的解決方案來解決,這將是創建一個屏幕外的畫布上繪製的路徑。

Canvas canvas2 = new Canvas(); 
Bitmap backingBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 


canvas2.setBitmap(backingBitmap); 
canvas2.drawPaint(clearPaint); 
canvas2.drawPath(path, linePaint); 
canvas2.drawPath(path, clearPaint); 

canvas.drawBitmap(backingBitmap, 0, 0, null); 

使用上面的方法,你會得到以下結果: Correct borders

缺點存在,創建位圖可能會降低性能,如果你正在做的每一幀。位圖的大小也會對性能產生不利影響。因此,只有在需要時才需要創建屏幕外畫布,只要不需要重置路徑信息,就可以繼續繪製到以前創建的backingBitmap上。

+0

謝謝你的插圖。我明白了你的觀點,但另一個非常致命的問題是這條線的交叉點:我需要知道哪條線位於頂部。如果仔細觀察我的圖像,你會發現交叉點與你的不同。 – Acheese

+0

啊,是的,我注意到在發佈我的答案時,但我無法弄清楚如何實現。如果我找到解決該問題的更好解決方案,我會更新我的答案。 –