自定义折线图,仿蚂蚁财富

  //不允许用户修改,想要修改宽高,使用mWidth、mBaseHeight。
    protected final float DEF_WIDTH = 650;
    protected final float DEF_HIGHT = 400;

    //测量的控件宽高,会在onMeasure中进行测量。
    protected int mBaseWidth;
    protected int mBaseHeight;
    private Paint mInnerXPaint;
    private Paint mLoadingPaint;
    private Paint mXYPaint;
    private Paint mLinePaint;
    private Paint dotPaint;
    //上下左右padding,允许修改
    //x、y轴指示文字字体的大小
    protected float mXYTextSize = 25;
    //左侧文字距离左边线线的距离
    protected float mLeftTxtPadding = 64;
    //底部文字距离底部线的距离
    protected float mBottomTxtPadding = 40;

    protected float mBasePaddingTop = 200;
    protected float mBasePaddingBottom = 200;
    protected float mBasePaddingLeft = 150;
    protected float mBasePaddingRight = 50;
    private ArrayList mPoints;
    private float mPerX;
    private float mPerY;

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

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

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

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthSpecMode == AT_MOST && heightSpecMode == AT_MOST) {
            setMeasuredDimension((int) DEF_WIDTH, (int) DEF_HIGHT);
        } else if (widthSpecMode == AT_MOST) {
            setMeasuredDimension((int) DEF_WIDTH, heightSpecSize);
        } else if (heightSpecMode == AT_MOST) {
            setMeasuredDimension(widthSpecSize, (int) DEF_HIGHT);
        } else {
            setMeasuredDimension(widthSpecSize, heightSpecSize);
        }
        mBaseWidth = getMeasuredWidth();
        mBaseHeight = getMeasuredHeight();
    }

    /**
     * 初始化各种画笔设置
     */
    private void init() {
        //初始化进度显示
        mLoadingPaint = new Paint();
        mLoadingPaint.setColor(getContext().getResources().getColor(R.color.colorAccent));
        mLoadingPaint.setTextSize(14);
        mLoadingPaint.setAntiAlias(true);
        //平行于x轴的
        mInnerXPaint = new Paint();
        mInnerXPaint.setColor(Color.LTGRAY);
        mInnerXPaint.setStrokeWidth(1);
        mInnerXPaint.setStyle(Paint.Style.STROKE);
        mInnerXPaint.setAntiAlias(true);
        //x轴y轴的实现
        mXYPaint = new Paint();
        mXYPaint.setColor(Color.GRAY);
        mXYPaint.setTextSize(25);
        mXYPaint.setAntiAlias(true);
        //折线
        mLinePaint = new Paint();
        mLinePaint.setColor(Color.RED);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setAntiAlias(true);
        mLinePaint.setTextSize(11);
        //买入卖出点
        dotPaint = new Paint();
        dotPaint.setColor(Color.BLUE);
        dotPaint.setStrokeWidth(1);
        dotPaint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //平行于X轴的横线
        drawInnerXPaint(canvas);
        //绘制xy轴的线
        drawXYPaint(canvas);
        //绘制折线图
        drawBrokenPaint(canvas);
        //绘制买入卖出点
        drawDot(canvas);
    }

    /**
     * 绘制买入卖出点
     *
     * @param canvas
     */
    private void drawDot(Canvas canvas) {
        //买入点假如是第五个点 卖出点假如是60个点
        float buyXDot = mBasePaddingLeft + (4 * mPerX);
        float buyYDot = (mBaseHeight - mBasePaddingTop) - (mPoints.get(4).y * mPerY);
        //先绘制买入点数据
        dotPaint.setStrokeWidth(Utils.dip2px(getContext(), 1));
        canvas.drawLine(buyXDot, buyYDot, buyXDot, buyYDot - Utils.dip2px(getContext(), 20), dotPaint);  //绘制红线
        dotPaint.setStrokeWidth(Utils.dip2px(getContext(), 4));
        canvas.drawCircle(buyXDot, buyYDot, Utils.dip2px(getContext(), 2), dotPaint); //绘制圆点
        dotPaint.setStrokeWidth(Utils.dip2px(getContext(), 0.5f));
        dotPaint.setStyle(Paint.Style.FILL);
        canvas.drawRect(buyXDot - Utils.dip2px(getContext(), 30), buyYDot - Utils.dip2px(getContext(), 26),
                buyXDot, buyYDot - Utils.dip2px(getContext(), 13), dotPaint);
        dotPaint.setTextSize(Utils.dip2px(getContext(), 11));
        dotPaint.setColor(Color.WHITE);
        canvas.drawText("买入", buyXDot - Utils.dip2px(getContext(), 30 / 2) - dotPaint.measureText("买入") / 2, buyYDot - Utils.dip2px(getContext(), 15), dotPaint);
        float saleXDot = mBasePaddingLeft + (20 * mPerX);
        float saleYDot = (mBaseHeight - mBasePaddingTop) - (mPoints.get(20).y * mPerY);
        //先绘制卖出点数据
        dotPaint.setColor(Color.GREEN);
        dotPaint.setStrokeWidth(Utils.dip2px(getContext(), 1));
        canvas.drawLine(saleXDot, saleYDot, saleXDot, saleYDot - Utils.dip2px(getContext(), 20), dotPaint);  //绘制红线
        dotPaint.setStrokeWidth(Utils.dip2px(getContext(), 4));
        canvas.drawCircle(saleXDot, saleYDot, Utils.dip2px(getContext(), 2), dotPaint); //绘制圆点
        dotPaint.setStrokeWidth(Utils.dip2px(getContext(), 0.5f));
        dotPaint.setStyle(Paint.Style.FILL);
        canvas.drawRect(saleXDot - Utils.dip2px(getContext(), 30), saleYDot - Utils.dip2px(getContext(), 26),
                saleXDot, saleYDot - Utils.dip2px(getContext(), 13), dotPaint);
        dotPaint.setTextSize(Utils.dip2px(getContext(), 11));
        dotPaint.setColor(Color.WHITE);
        canvas.drawText("卖出", saleXDot - Utils.dip2px(getContext(), 30 / 2) - dotPaint.measureText("卖出") / 2, saleYDot - Utils.dip2px(getContext(), 15), dotPaint);

    }
        private void drawInnerXPaint (Canvas canvas){
            //画5条横轴的虚线
            //首先确定最大值和最小值的位置
            float perHight = (mBaseHeight - mBasePaddingBottom - mBasePaddingTop) / 4;
            //绘制基准线
            canvas.drawLine(0 + mBasePaddingLeft, mBasePaddingTop,
                    mBaseWidth - mBasePaddingRight, mBasePaddingTop, mInnerXPaint);//最上面的那一条

            canvas.drawLine(0 + mBasePaddingLeft, mBasePaddingTop + perHight * 1,
                    mBaseWidth - mBasePaddingRight, mBasePaddingTop + perHight * 1, mInnerXPaint);//2

            canvas.drawLine(0 + mBasePaddingLeft, mBasePaddingTop + perHight * 2,
                    mBaseWidth - mBasePaddingRight, mBasePaddingTop + perHight * 2, mInnerXPaint);//3

            canvas.drawLine(0 + mBasePaddingLeft, mBasePaddingTop + perHight * 3,
                    mBaseWidth - mBasePaddingRight, mBasePaddingTop + perHight * 3, mInnerXPaint);//4

            canvas.drawLine(0 + mBasePaddingLeft, mBaseHeight - mBasePaddingBottom,
                    mBaseWidth - mBasePaddingRight, mBaseHeight - mBasePaddingBottom, mInnerXPaint);//最下面的那一条

        }

        private void drawXYPaint (Canvas canvas){
            //先处理y轴方向文字
            //现将最小值、最大值画好
            Paint.FontMetrics fontMetrics = mXYPaint.getFontMetrics();
            float height = fontMetrics.descent - fontMetrics.ascent;
            //draw min
            float txtWigth = Utils.dip2px(getContext(), 10) + mLeftTxtPadding;

            //因为横线是均分的,所以只要取到最大值最小值的差值,均分即可。
            float perYWidth = (mBaseHeight - mBasePaddingBottom - mBasePaddingTop) / 4;
            //从下到上依次画
            for (int i = 0; i < 5; i++) {
                canvas.drawText((20 * i) + "",
                        mBasePaddingLeft - txtWigth,
                        mBaseHeight - mBasePaddingBottom - perYWidth * i + height / 2, mXYPaint);
            }

            //处理x轴方向文字
            //x轴文字的高度
            float hight = mBaseHeight - mBasePaddingBottom + mBottomTxtPadding;

            //绘制X轴文字
            float space = (mBaseWidth - mBasePaddingLeft - mBasePaddingRight - mXYPaint.measureText("2020-02-02") * 2 - mXYPaint.measureText("2020-02-02") / 2) / 2;  //刨去文字剩余的空间
            canvas.drawText("2020-02-02", mBasePaddingLeft - mXYPaint.measureText("2020-02-02") / 2, hight, mXYPaint);
            canvas.drawText("2020-02-04", mBasePaddingLeft + space + mXYPaint.measureText("2020-02-02") / 2, hight, mXYPaint);
            canvas.drawText("2020-02-06", mBaseWidth - mBasePaddingRight - mXYPaint.measureText("2020-02-02"), hight, mXYPaint);
        }

        private void drawBrokenPaint (Canvas canvas){
            mPerX = (mBaseWidth - mBasePaddingLeft - mBasePaddingRight) / mPoints.size();
            mPerY = ((mBaseHeight - mBasePaddingTop - mBasePaddingBottom) / 80);
            Path path = new Path();
            path.moveTo(mBasePaddingLeft, (mBaseHeight - mBasePaddingTop) - (mPoints.get(0).y * mPerY));
            for (int i = 1; i < mPoints.size(); i++) {
                path.lineTo(mBasePaddingLeft + (i * mPerX), (mBaseHeight - mBasePaddingTop) - (mPoints.get(i).y * mPerY));
            }
            canvas.drawPath(path, mLinePaint);

        }

        public void setData (ArrayList < Point > points) {
            this.mPoints = points;
            invalidate();
        }

github地址为https://github.com/yybDream/ChartView/tree/master

你可能感兴趣的:(自定义折线图,仿蚂蚁财富)