Path曲线下的阴影绘制

开发动机

我们经常使用MPchart来绘制各种类型的图表,非常好用。可以设置各种各样的样式。但是有时候满足不了我们的需求或者我们需要绘制的曲线很简单但是MPchart jar包不小,所以我们需要自定义view自己来绘制Path实现。通过Path绘制曲线比较简单,但是Path下的阴影还没有去实现过。

开发思路

绘制曲线比较简单,Path有方法可以直接绘制:
public void lineTo(float x, float y) 用来绘制直线
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)用来绘制曲线
我比较疑惑的是曲线下面的阴影应该怎么绘制。我们知道可以使用drawable.draw(canvas)来绘制Drawable,Drawable可以使用Shape来创建。那么Drawable怎么在Path的范围之内呢?稍微想一想就知道肯定把canvas切割成一个形状,然后在该canvas上绘制Drawable就能实现。于是去看了下MPchart的源码,发现很简单。
有一个核心方法是用Path切割画布:

    /**
     * Intersect the current clip with the specified path.
     *
     * @param path The path to intersect with the current clip
     * @return     true if the resulting is non-empty
     */
    public boolean clipPath(@NonNull Path path) {
        return clipPath(path, Region.Op.INTERSECT);
    }

所以,实现的代码就出来了。

开发实现

这里写图片描述

public class PathLineView extends View {

    //mPath用于画线
    private Path mPath = new Path();
    //mFillPath用于封闭后形成一个图形去切割画布
    private Path mFillPath = new Path();
    private Paint mPaint = new Paint();
    private int mViewWidth;
    private int mViewHeight;

    public PathLineView(Context context) {
        this(context, null);
    }

    public PathLineView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PathLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        int fillAlpha = 255;
        int fillColor = getResources().getColor(R.color.text_color_4a4a4a);
        int color = (fillAlpha << 24) | (fillColor & 0xffffff);
        mPaint.setColor(color);
        mPaint.setStrokeWidth(6);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
        mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //x轴
        canvas.drawLine(0, mViewHeight, mViewWidth, mViewHeight, mPaint);
        //y轴
        canvas.drawLine(0, 0, 0, mViewHeight, mPaint);


        float startX = 150;
        float startY = 200;
        float topY = 150;
        float endX = 500;
        float endY = 150;
        mPath.reset();
        mPath.moveTo(startX,startY);
        mPath.lineTo(300,topY);
        mPath.lineTo(endX,endY);
        canvas.drawPath(mPath,mPaint);
        //绘制封闭Path用于切割
        mFillPath.reset();
        mFillPath.addPath(mPath);
        mFillPath.lineTo(endX,mViewHeight);
        mFillPath.lineTo(startX,mViewHeight);
        mFillPath.close();

        //默认开启硬件加速的情况下 clipPath 需要SDK >18
        //如果关闭硬件加速,则不需要SDK要求
        if(clipPathSupported()) {
            int save = canvas.save();
            //将画布切割成path的形状
            canvas.clipPath(mFillPath);

            Drawable drawable = getFillDrawable();
            drawable.setBounds((int)startX,(int)topY,mViewWidth,mViewHeight);
            drawable.draw(canvas);
            canvas.restoreToCount(save);
        }else{
            canvas.drawPath(mPath, mPaint);
        }

    }


    /**
     * Clip path with hardware acceleration only working properly on API level 18 and above.
     *
     * @return
     */
    private boolean clipPathSupported() {
        return CommonUtils.getSDKInt() >= 18;
    }

    private Drawable getFillDrawable(){
        return getResources().getDrawable(R.drawable.path_fill_red);
    }

}

具体代码见Demo:https://github.com/xindasunday/ShareDemo


版权声明:本文为Vxiaocai原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。