Android Custom可绘画笔画不同宽度

时间:2016-09-22 13:14:08

标签: android drawable

在drawable上绘制路径并将drawable设置为View / ImageView的背景或src时出现问题。似乎正在发生的事情是,我做箭头的一侧的路径总是比直线稍厚......我正在测试具有固定尺寸的视图。任何人都有关于我如何解决它的想法?

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

}

1 个答案:

答案 0 :(得分: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;
    }

}