2016-09-22 17 views
1

描画可能にパスを描画し、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

(最初申し訳ストローク幅/ 2 – pskink

+0

によってbounddオフセットが、私はあなたが示唆されているものを得ることはありません申し訳ありません – DArkO

+0

:はめ込み、bounds.inset(strokeWidth/2)を呼び出す – pskink

答えて

0

私は以下の描画可能コードでこの作業を行っています。 しかし、これは境界の外に矢印を描きます。私は私が背景としてそれを置くビューにパディングを追加する必要がないように私は意図的にやった。背景をクリップしないように、ビューの親コンテナにいくつかのフラグを設定するだけでした。

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

これは、左矢印と右矢印のドロウアブルでは正常に機能しているようです。 pointLeftで

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; 
    } 

} 
+1

あなたは 'Drawable's boundsの外に描画しています。悪いアイデアは、右矢印:http://pastebin.com/YvXrTYVfのためにそれをどうすべきかを見て、最も重要な変更は 'newRect.inset(strokeWidth/2、strokeWidth/2);'行です。特別なパディングや 'android:clip *'が 'false'に設定されている必要があります – pskink

+0

ええ、それ以外はそうですビューのコンテンツにパディングを追加します。すべてが適切な状態で適切に配置されるので、これは私の特定のユースケースでうまく機能します。私は動作するように見える境界内に描画していたバージョンを持っていましたが、挿入図は関係なく、おいしいトリックです! – DArkO

+0

'Drawable#getPadding'をオーバーライドすると、ビューのパディングは不要です – pskink

関連する問題