2016-09-22 97 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