Android纯手工实现几种数据趋势图(超简单,有源码)

445 阅读1分钟

不需要依赖第三方框架,直接使用Canvas

drawLine,drawPath,drawCircle 

等几个简单的API即可搞定

效果图

result.gif

源码 github.com/woshiwzy/tr…

部分代码节选

onDraw


protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    w = getWidth();
    h = getHeight();
    this.coordinate_pading_v = (int) (h * this.coordinate_pading_v_percent);
    canvas.drawColor(Color.WHITE);
    mPaint.setStrokeWidth(paintSolideSmall);
    mPaint.setTextSize(label_text_size);
    int title_width = (int) mPaint.measureText(this.titlle);
    mPaint.setStyle(Style.FILL);
    mPaint.setColor(Color.BLACK);
    canvas.drawText(this.titlle, w / 2 - title_width / 2, 50, mPaint);
    // 画背景网格
    if (0 == (countListSize(mArrayListHolderAllLastYear) + countListSize(mArrayListHolderAllThisYear) +
            countListSize(mArrayListHolderLocalLastYears) + countListSize(mArrayListHolderLocalThisYears))) {
    } else {
        drawGrid(canvas);
    }
}

drawGrid 回执主要内容

public void drawGrid(Canvas canvas) {
    mPaint.setColor(0x33dbdbdb);
    // 画垂直网格
    // coordinate_pading_h
    int cell_width = (w - coordinate_pading_h * 2) / (months - 1);

    this.mPointsAll.clear();
    this.mPointsLocal.clear();
    float pix_value_unit = (h - h * coordinate_pading_v_percent - coordinate_pading_b) / (this.highest - this.lowerest);

    Path pathLocalThis = new Path();//本公司今年
    pathLocalThis.reset();

    Path pathLocalLast = new Path();//本公司去年
    pathLocalLast.reset();


    Path pathAllThis = new Path();//全市场今年
    pathAllThis.reset();

    Path pathAllLast = new Path();//全市场去年
    pathAllLast.reset();


    for (int i = 0, isize = months; i < isize; i++) {
        int startX = coordinate_pading_h + i * cell_width;
        int startY = 0;
        int stopX = coordinate_pading_h + i * cell_width;
        int stopY = h;
        canvas.drawLine(startX, startY, stopX, stopY, mPaint);// 竖直网格
        canvas.drawLine(startX + cell_width / 2, startY, startX + cell_width / 2, stopY, mPaint);// 竖直网格
        if (i == 0) {
            canvas.drawLine(startX - cell_width / 2, startY, startX - cell_width / 2, stopY, mPaint);// 竖直网格
        }

        if (null != mArrayListHolderLocalThisYears && !mArrayListHolderLocalThisYears.isEmpty()) {
            //本公司今年
            if (i < mArrayListHolderLocalThisYears.size()) {
                Holder holderLocalThisYear = mArrayListHolderLocalThisYears.get(i);
                if (null == this.mPointsLocal) {
                    this.mPointsLocal = new ArrayList<MyPoint>();
                }
                int x = startX;
                float y = h - pix_value_unit * (holderLocalThisYear.getValue() - this.lowerest) - coordinate_pading_b;
                MyPoint mypointlocalthisyear = new MyPoint(x, (int) y, holderLocalThisYear);
                if (i == 0) {
                    pathLocalThis.moveTo(x, y);
                } else {
                    pathLocalThis.lineTo(x, y);
                }
                this.mPointsLocal.add(mypointlocalthisyear);
            } else {
                this.mPointsLocal = null;
            }
        }
        if (null != mArrayListHolderLocalLastYears && !mArrayListHolderLocalLastYears.isEmpty()) {
            //本公司去年
            if (i < mArrayListHolderLocalLastYears.size()) {
                Holder holderLocalLastYear = mArrayListHolderLocalLastYears.get(i);
                if (null == this.mPointsLast) {
                    this.mPointsLast = null;
                }
                int x = startX;
                float y = h - pix_value_unit * (holderLocalLastYear.getValue() - this.lowerest) - coordinate_pading_b;
                MyPoint mypointlocallastyear = new MyPoint(x, (int) y, holderLocalLastYear);
                if (i == 0) {
                    pathLocalLast.moveTo(x, y);
                } else {
                    pathLocalLast.lineTo(x, y);
                }
                this.mPointsLast.add(mypointlocallastyear);
            } else {
                this.mPointsLast = null;
            }
        }

        if (null != mArrayListHolderAllThisYear && !mArrayListHolderAllThisYear.isEmpty()) {
            //全市场今年
            if (i < mArrayListHolderAllThisYear.size()) {
                Holder holderAllHolderThisYear = mArrayListHolderAllThisYear.get(i);
                if (null == this.mPointsAll) {
                    this.mPointsAll = new ArrayList<MyPoint>();
                }
                int x = startX;
                float y = h - pix_value_unit * (holderAllHolderThisYear.getValue() - this.lowerest) - coordinate_pading_b;
                MyPoint mypointallthisyear = new MyPoint(x, (int) y, holderAllHolderThisYear);
                if (i == 0) {
                    pathAllThis.moveTo(x, y);
                } else {
                    pathAllThis.lineTo(x, y);
                }
                this.mPointsAll.add(mypointallthisyear);
            } else {
                this.mPointsAll = null;
            }
        }

        if (null != mArrayListHolderAllLastYear && !mArrayListHolderAllLastYear.isEmpty()) {
            //全市场去年
            if (i < mArrayListHolderAllLastYear.size()) {
                Holder holderAllHolderLastYear = mArrayListHolderAllLastYear.get(i);
                if (null == this.mPointsAllLast) {
                    this.mPointsAllLast = new ArrayList<MyPoint>();
                }
                int x = startX;
                float y = h - pix_value_unit * (holderAllHolderLastYear.getValue() - this.lowerest) - coordinate_pading_b;
                MyPoint mypointalllastyear = new MyPoint(x, (int) y, holderAllHolderLastYear);
                if (i == 0) {
                    pathAllLast.moveTo(x, y);
                } else {
                    pathAllLast.lineTo(x, y);
                }
                this.mPointsAllLast.add(mypointalllastyear);
            } else {
                this.mPointsAllLast = null;
            }
        }
    }

    //组装path结束
    // 画水平网格
    int cell_height = h / (months * 2);
    for (int i = 0, isize = months * 2; i <= isize; i++) {
        canvas.drawLine(0, cell_height * i, w, cell_height * i, mPaint);
    }
    mPaint.setStyle(Style.STROKE);
    mPaint.setStrokeWidth(radiusBig);

    mPaint.setColor(0xff667788);//
    canvas.drawPath(pathLocalThis, mPaint);

    mPaint.setColor(0xff908765);//
    canvas.drawPath(pathLocalLast, mPaint);

    mPaint.setColor(0xff114477);//
    canvas.drawPath(pathAllThis, mPaint);

    mPaint.setColor(0xff765432);//
    canvas.drawPath(pathAllLast, mPaint);

    mPaint.setColor(0xffdbe4e6);
    mPaint.setStyle(Style.FILL);

    // canvas.drawLine(0, h-coordinate_pading_b, w, h-coordinate_pading_b, mPaint);
    canvas.drawRect(0, h - coordinate_pading_b / 2, w, h, mPaint);// 标注x刻度
    mPaint.setColor(Color.BLACK);
    mPaint.setTextSize((label_text_size / 3) * 2);

    ArrayList<MyPoint> locationPoints = getNotNullPointList();
    if (locationPoints != null) {
        for (int i = 0, isize = months; i < isize; i++) {
            MyPoint p = locationPoints.get(i);
            canvas.drawText(p.getHolder().getStamp(), p.x - 5, h - coordinate_pading_b / 2 + 25, mPaint);
        }
    }

    mPaint.setStrokeWidth(paintSolideBig / 2);
    mPaint.setColor(0xffb0b9c2);// 底部分割线
    canvas.drawLine(0, h, w, h, mPaint);
    mPaint.setStrokeWidth(paintSolideBig);

    if (isSetting) {
        ArrayList<MyPoint> templist = getNotNullPointList();
        if (null != templist) {
            // 找到第一个点
            if (this.startIndex < templist.size()) {
                MyPoint startPoint = templist.get(this.startIndex);
                drawMoveLine(canvas, startPoint, cell_width);
                //画第二根线
                if (endIndex < startIndex) {
                    endIndex = startIndex + 1;
                }
                if (endIndex < templist.size() && templist.size() > 1) {
                    MyPoint endPoint = templist.get(endIndex);
                    drawMoveLine(canvas, endPoint, cell_width);
                    drawRectransparent(canvas, startPoint, endPoint);
                }

            }
        }
    } else {
        ArrayList<MyPoint> notNullPoints = getNotNullPointList();
        Object rets[] = findNearestPoint(notNullPoints);
        if (rets.length > 1) {
            MyPoint nearestPoint = (MyPoint) rets[0];//最近的触摸点
            //第一个点距离触摸点的
            if (1 == notNullPoints.size()) {
                mPaint.setColor(0xff34DE71);
                drawMoveLine(canvas, nearestPoint, cell_width);
            } else {
                if (startIndex < 0) {
                    startIndex = 0;
                }
                if (endIndex < startIndex) {
                    endIndex = startIndex + 1;
                }
                if (endIndex >= notNullPoints.size()) {
                    endIndex = notNullPoints.size() - 1;
                }
                if (startIndex >= 0 && startIndex < endIndex) {
                    //找到离触摸点最近的点
                    float dstart = cputeDistanceX(mTouchPoint, notNullPoints.get(this.startIndex));
                    float dend = cputeDistanceX(mTouchPoint, notNullPoints.get(this.endIndex));
                    int index = (Integer) rets[1];
                    if (dstart < dend) {
                        //将起始点移动到触摸点   ,备注:效果图要求不移动
                        this.startIndex = index;
                    }
                    if (dstart > dend) {
                        //将结束点移动到触摸点
                        this.endIndex = index;
                    }
                    MyPoint startPoint = notNullPoints.get(this.startIndex);
                    MyPoint endPoint = notNullPoints.get(this.endIndex);
                    drawMoveLine(canvas, startPoint, cell_width);//画第一根线
                    drawMoveLine(canvas, endPoint, cell_width);//画第二根线
                    drawRectransparent(canvas, startPoint, endPoint);//画半透明区域
                }
            }
            if (null != moveListener) {
                moveListener.onMove(this.endIndex);
            }
        }
    }


}