2016-09-22 93 views
1

我在繪製drawable上的路徑並將drawable設置爲View/ImageView的背景或src時存在問題。似乎正在發生的事情是,我做箭頭的一側的路徑總是比直線粗一點......我正在測試具有固定尺寸的視圖。任何人有想法如何我可以修復它?Android自定義繪製筆畫不同寬度

Result

這裏是我的代碼繪製的。

public class ArrowDrawable extends Drawable { 

    public static final String TAG = ArrowDrawable.class.getSimpleName(); 

    private Paint outlinePaint; 
    private Paint fillPaint; 

    int padding = 40; 
    int arrowPosition = 50; 
    int arrowHeight = 60; 
    int strokeWidth = 10; 
    Path path = new Path(); 

    public enum Direction { 
     RIGHT, 
     LEFT; 
    } 

    Direction direction = Direction.RIGHT; 

    public ArrowDrawable() { 
     init(); 
    } 

    private void init() { 
     outlinePaint = new Paint(); 
     outlinePaint.setStyle(Paint.Style.STROKE);  // set to STOKE 
     outlinePaint.setStrokeJoin(Paint.Join.BEVEL); // set the join to round you want 
     outlinePaint.setStrokeCap(Paint.Cap.ROUND);  // set the outlinePaint cap to round too 
     outlinePaint.setPathEffect(new CornerPathEffect(2)); // set the path effect when they join. 
     outlinePaint.setAntiAlias(true); 
     outlinePaint.setStrokeWidth(strokeWidth); 

     fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     fillPaint.setStrokeWidth(strokeWidth); 
     fillPaint.setStrokeJoin(Paint.Join.ROUND); 
     fillPaint.setPathEffect(new CornerPathEffect(2)); 
     fillPaint.setStyle(Paint.Style.FILL); 
     fillPaint.setAntiAlias(true); 
     fillPaint.setColor(Color.WHITE); 
    } 


    public void setDirection(Direction direction) { 
     this.direction = direction; 
     invalidateSelf(); 
    } 

    public void setStrokeColor(int color) { 
     outlinePaint.setColor(color); 
     invalidateSelf(); 
    } 

    public void setFillColor(int color) { 
     fillPaint.setColor(color); 
     invalidateSelf(); 
    } 

    public void setPadding(int padding) { 
     this.padding = padding; 
     invalidateSelf(); 
    } 

    public void setArrowPosition(int arrowPosition) { 
     this.arrowPosition = arrowPosition; 
     invalidateSelf(); 
    } 

    public void setArrowHeight(int arrowHeight) { 
     this.arrowHeight = arrowHeight; 
     invalidateSelf(); 
    } 

    public void setStrokeWidth(int strokeWidth) { 
     this.strokeWidth = strokeWidth; 
     invalidateSelf(); 
    } 

    @Override 
    public void draw(Canvas canvas) { 



     final Rect bounds = getBounds(); 
     Log.d(TAG, "draw: " + canvas.getWidth() + " " + canvas.getHeight()); 
     Path path; 
     if (direction == Direction.RIGHT) { 
      path = pointRight(bounds); 
     } else if (direction == Direction.LEFT) { 
      path = pointLeft(bounds); 
     } else { 
      throw new IllegalArgumentException("Direction is not supported"); 
     } 
     path.computeBounds(new RectF(bounds), false); 
     canvas.drawPath(path, outlinePaint); 
    } 

    @Override 
    public void invalidateSelf() { 
     path = null; 
     super.invalidateSelf(); 
    } 

    @Override 
    protected void onBoundsChange(Rect bounds) { 
     super.onBoundsChange(bounds); 
     invalidateSelf(); 
    } 

    public Path pointRight(Rect bounds) { 
     if (path != null) { 
      return path; 
     } 
     final Rect newRect = new Rect(bounds.left, bounds.top, bounds.right - padding - strokeWidth, bounds.bottom); 
     path = new Path(); 
     path.moveTo(newRect.left, newRect.top); 
     path.lineTo(newRect.right, newRect.top); 

     path.lineTo(newRect.right, newRect.top + arrowPosition); 
     path.lineTo(bounds.right - strokeWidth, newRect.top + arrowPosition + arrowHeight/2.0f); 
     path.lineTo(newRect.right, newRect.top + arrowPosition + arrowHeight); 

     path.lineTo(newRect.right, newRect.bottom); 
     path.lineTo(newRect.left, newRect.bottom); 
     path.close(); 
     return path; 
    } 

    public Path pointLeft(Rect bounds) { 
     if (path != null) { 
      return path; 
     } 
     final Rect newRect = new Rect(bounds.left + padding + strokeWidth, bounds.top, bounds.right, bounds.bottom); 
     path = new Path(); 
     path.moveTo(newRect.left, newRect.top); 

     path.lineTo(newRect.left, newRect.top + arrowPosition); 
     path.lineTo(bounds.left + strokeWidth, newRect.top + arrowPosition + arrowHeight/2.0f); 
     path.lineTo(newRect.left, newRect.top + arrowPosition + arrowHeight); 

     path.lineTo(newRect.left, newRect.bottom); 
     path.lineTo(newRect.right, newRect.bottom); 
     path.lineTo(newRect.right, newRect.top); 
     path.close(); 

     return path; 
    } 

    @Override 
    public void setAlpha(int alpha) { 

    } 

    @Override 
    public void setColorFilter(ColorFilter colorFilter) { 

    } 

    @Override 
    public int getOpacity() { 
     return PixelFormat.UNKNOWN; 
    } 

} 
+0

但我不明白你的建議是什麼 – pskink

+0

對不起第一偏移boundd – DArkO

+0

遺憾:插圖,調用bounds.inset(strokeWidth/2) – pskink

回答

0

所以我用下面的可繪製代碼做了這個工作。但是這會在邊界外繪製箭頭。我的目的是什麼,以便我不必將填充添加到視圖中,我把它作爲背景。我只需在視圖的父容器上設置幾個標記以不剪切背景。

android:clipChildren="false" 
android:clipToPadding="false" 

這似乎現在工作正常,左側和右側箭頭可繪製。

public class ArrowDrawable extends Drawable { 

    public static final String TAG = ArrowDrawable.class.getSimpleName(); 

    private Paint outlinePaint; 
    private Paint fillPaint; 

    private int padding = 40; 
    private int arrowPosition = 50; 
    private int arrowHeight = 60; 
    private int strokeWidth = 4; 
    Path path; 

    public enum Direction { 
     RIGHT, 
     LEFT 
    } 

    Direction direction = Direction.RIGHT; 

    public ArrowDrawable() { 
     init(); 
    } 

    private void init() { 
     outlinePaint = new Paint(); 
     outlinePaint.setDither(true);     // set the dither to true 
     outlinePaint.setStyle(Paint.Style.STROKE);  // set to STOKE 
     outlinePaint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want 
     outlinePaint.setStrokeCap(Paint.Cap.ROUND);  // set the outlinePaint cap to round too 
     outlinePaint.setPathEffect(new CornerPathEffect(2)); // set the path effect when they join. 
     outlinePaint.setAntiAlias(true); 

     fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     fillPaint.setStrokeJoin(Paint.Join.ROUND); 
     fillPaint.setPathEffect(new CornerPathEffect(2)); 
     fillPaint.setStyle(Paint.Style.FILL); 
     fillPaint.setAntiAlias(true); 
     fillPaint.setColor(Color.TRANSPARENT); 
    } 


    public void setDirection(Direction direction) { 
     this.direction = direction; 
     invalidateSelf(); 
    } 

    public void setStrokeColor(int color) { 
     outlinePaint.setColor(color); 
     invalidateSelf(); 
    } 

    public void setFillColor(int color) { 
     fillPaint.setColor(color); 
     invalidateSelf(); 
    } 

    public void setPadding(int padding) { 
     this.padding = padding; 
     invalidateSelf(); 
    } 

    public void setArrowPosition(int arrowPosition) { 
     this.arrowPosition = arrowPosition; 
     invalidateSelf(); 
    } 

    public void setArrowHeight(int arrowHeight) { 
     this.arrowHeight = arrowHeight; 
     invalidateSelf(); 
    } 

    public void setStrokeWidth(int strokeWidth) { 
     this.strokeWidth = strokeWidth; 
     invalidateSelf(); 
    } 

    @Override 
    protected void onBoundsChange(Rect bounds) { 
     super.onBoundsChange(bounds); 
     recalculatePath(bounds); 
    } 

    private void recalculatePath(Rect bounds) { 
     if (direction == Direction.RIGHT) { 
      path = pointRight(bounds); 
     } else if (direction == Direction.LEFT) { 
      path = pointLeft(bounds); 
     } else { 
      throw new IllegalArgumentException("Direction is not supported"); 
     } 
    } 

    @Override 
    public void draw(Canvas canvas) { 
     if (path == null) { 
      return; 
     } 
     outlinePaint.setStrokeWidth(strokeWidth); 
     fillPaint.setStrokeWidth(strokeWidth); 
     canvas.drawPath(path, fillPaint); 
     canvas.drawPath(path, outlinePaint); 
    } 

    @Override 
    public void invalidateSelf() { 
     recalculatePath(getBounds()); 
     super.invalidateSelf(); 
    } 

    public Path pointRight(Rect bounds) { 
     final Rect newRect = new Rect(bounds.left, bounds.top, bounds.right, bounds.bottom); 
     path = new Path(); 
     path.moveTo(newRect.left, newRect.top); 
     path.lineTo(newRect.right, newRect.top); 

     path.lineTo(newRect.right, newRect.top + arrowPosition); 
     path.lineTo(bounds.right + padding - strokeWidth, newRect.top + arrowPosition + arrowHeight/2.0f); 
     path.lineTo(newRect.right, newRect.top + arrowPosition + arrowHeight); 

     path.lineTo(newRect.right, newRect.bottom); 
     path.lineTo(newRect.left, newRect.bottom); 
     path.close(); 
     return path; 
    } 

    public Path pointLeft(Rect bounds) { 
     final Rect newRect = new Rect(bounds.left, bounds.top, bounds.right, bounds.bottom); 
     path = new Path(); 
     path.moveTo(newRect.left, newRect.top); 

     path.lineTo(newRect.left, newRect.top + arrowPosition); 
     path.lineTo(bounds.left - padding + strokeWidth, newRect.top + arrowPosition + arrowHeight/2.0f); 
     path.lineTo(newRect.left, newRect.top + arrowPosition + arrowHeight); 

     path.lineTo(newRect.left, newRect.bottom); 
     path.lineTo(newRect.right, newRect.bottom); 
     path.lineTo(newRect.right, newRect.top); 
     path.close(); 

     return path; 
    } 

    @Override 
    public void setAlpha(int alpha) { 

    } 

    @Override 
    public void setColorFilter(ColorFilter colorFilter) { 

    } 

    @Override 
    public int getOpacity() { 
     return PixelFormat.UNKNOWN; 
    } 

} 
在pointLeft(按筆畫寬度/ 2
+1

你正在繪製的外部'Drawable's bounds which is a不好的主意,看看你應該怎麼做,對於右箭頭:http://pastebin.com/YvXrTYVf,最重要的變化是'newRect.inset(strokeWidth/2,strokeWidth/2);'線,這樣就沒有需要額外的視圖填充,也沒有'android:clip *'設置爲'false' – pskink

+0

是的,但是否則我是ne編輯添加填充視圖的內容。這對我的特定用例更好,因爲所有東西都可以在開箱即用的情況下正確對齊。我有一個版本,我正在繪製的界限內也似乎工作,插入是一個很好的技巧不管,謝謝! – DArkO

+0

覆蓋'Drawable#getPadding'然後,不需要視圖填充 – pskink