昨天晚上跟朋友聊天,聊到绘制折线,然后多画了几笔,画了个折线图。(老规矩后面有源码)

先看一下效果图

Android用Canvas画一个折线图,并加以简单封装_Canvas

Android用Canvas画一个折线图,并加以简单封装_Canvas_02

view宽高设置为正方形

Android用Canvas画一个折线图,并加以简单封装_折线图_03

view宽高设置为mach_parent

先来绘制一个固定的折线图

1.先画一个xy坐标轴。

Paint daxesPaint,axispointPaint,brokenLinePaint;
        //画布宽度
        canvasWidth = canvas.getWidth();
        //画布高度
        canvasHeight = canvas.getHeight();
        widthCriterion = canvasWidth /10;    //将画布宽分为10份
        hightCriterion = canvasHeight /10;   //将画布高分为10份
        minCriterion = widthCriterion > hightCriterion ? hightCriterion /2: widthCriterion /2; //画xy轴角的依据
       
        daxesPaint=new Paint();
        daxesPaint.setColor(Color.BLACK);
        daxesPaint.setAntiAlias(true);  //去掉锯齿效果
        daxesPaint.setStrokeWidth(7.0f);//画笔宽度
        //第一个方法:画xy轴
        drawDaxes(canvas,daxesPaint);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
drawDaxes方法如下:
  • 1.
private void  drawDaxes(Canvas canvas,Paint p){
       //开始y绘制坐标系
       canvas.drawLine(widthCriterion,hightCriterion,widthCriterion,hightCriterion*9,p);
       //绘制y角
       canvas.drawLine(widthCriterion-minCriterion,hightCriterion+minCriterion,widthCriterion+2,hightCriterion,p);
       canvas.drawLine(widthCriterion,hightCriterion,widthCriterion+minCriterion-2,hightCriterion+minCriterion,p);
       //开始x绘制坐标系
       canvas.drawLine(widthCriterion-4,hightCriterion*9,widthCriterion*9,hightCriterion*9,p);
       //绘制x角
       canvas.drawLine(widthCriterion*9-minCriterion,hightCriterion*9-minCriterion,widthCriterion*9,hightCriterion*9+2,p);
       canvas.drawLine(widthCriterion*9-minCriterion,hightCriterion*9+minCriterion,widthCriterion*9,hightCriterion*9-2,p);

   }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

效果如下:

Android用Canvas画一个折线图,并加以简单封装_折线_04

2.再绘制x,y轴坐标

//开始绘制xy轴坐标
        axispointPaint=daxesPaint;
        drawAxispoint(canvas,axispointPaint);
  • 1.
  • 2.
  • 3.

drawAxispoint方法如下

private void drawAxispoint(Canvas canvas,Paint p){
       textFont=widthCriterion/5*2;
       Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
       p.setTypeface( font );
       p.setTextSize(textFont);
       for (int i = 1; i <=8 ; i++) {
           String text= String.valueOf(-1+i);
           int stringWidth = (int) p.measureText(text);     //文本长度
           canvas.drawText(text, i*widthCriterion-stringWidth/2, hightCriterion*9+textFont, p);// 画文本
       }
       for (int i = 1; i <=7 ; i++) {
           String text= String.valueOf(i);
           int stringWidth = (int) p.measureText(text);
           //文本长度
           canvas.drawText(text, widthCriterion-textFont, hightCriterion*9-i*hightCriterion+stringWidth/2, p);// 画文本
       }
   }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

效果图如下:

Android用Canvas画一个折线图,并加以简单封装_折线_05

3.最后绘制折线和坐标点

//开始绘制折线和坐标点
        brokenLinePaint=axispointPaint;
        brokenLinePaint.setStrokeWidth(5.0f);
        drawbrokenLine(canvas,brokenLinePaint);
  • 1.
  • 2.
  • 3.
  • 4.

drawbrokenLine方法如下:

private void drawbrokenLine(Canvas canvas,Paint p){
       canvas.drawLine(widthCriterion,hightCriterion*9,widthCriterion*2,hightCriterion*2,p);
       canvas.drawLine(widthCriterion*2,hightCriterion*2,widthCriterion*3,hightCriterion*5,p);
       canvas.drawLine(widthCriterion*3,hightCriterion*5,widthCriterion*4,hightCriterion*7,p);
       canvas.drawLine(widthCriterion*4,hightCriterion*7,widthCriterion*5,hightCriterion*6,p);
       canvas.drawLine(widthCriterion*5,hightCriterion*6,widthCriterion*6,hightCriterion*7,p);
       canvas.drawLine(widthCriterion*6,hightCriterion*7,widthCriterion*7,hightCriterion*2,p);
       canvas.drawLine(widthCriterion*7,hightCriterion*2,widthCriterion*8,hightCriterion*3,p);
       //画折线上的点
       canvas.drawCircle(widthCriterion, hightCriterion*9, 10, p);
       canvas.drawCircle(widthCriterion*2,hightCriterion*2, 10, p);
       canvas.drawCircle(widthCriterion*3,hightCriterion*5, 10, p);
       canvas.drawCircle(widthCriterion*4,hightCriterion*7, 10, p);
       canvas.drawCircle(widthCriterion*5,hightCriterion*6, 10, p);
       canvas.drawCircle(widthCriterion*6,hightCriterion*7, 10, p);
       canvas.drawCircle(widthCriterion*7,hightCriterion*2, 10, p);
       canvas.drawCircle(widthCriterion*8,hightCriterion*3, 10, p);

   }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

效果图如下:

Android用Canvas画一个折线图,并加以简单封装_折线_06

固定的折线图java文件如下:

public class LineChartView extends View {

    private int minCriterion;
    private int hightCriterion;
    private int widthCriterion;
    private int canvasHeight;
    private int canvasWidth;
    private int textFont;


    public LineChartView(Context context) {
        super(context);
    }

    public LineChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawAxis(canvas);
    }

    //绘制
    private void drawAxis(Canvas canvas){
        Paint daxesPaint,axispointPaint,brokenLinePaint;
        //画布宽度
        canvasWidth = canvas.getWidth();
        //画布高度
        canvasHeight = canvas.getHeight();
        widthCriterion = canvasWidth /10;    //将画布宽分为10份
        hightCriterion = canvasHeight /10;   //将画布高分为10份
        minCriterion = widthCriterion > hightCriterion ? hightCriterion /2: widthCriterion /2; //画xy轴角的依据

        daxesPaint=new Paint();
        daxesPaint.setColor(Color.BLACK);
        daxesPaint.setAntiAlias(true);  //去掉锯齿效果
        daxesPaint.setStrokeWidth(7.0f);//画笔宽度
        //第一个方法:画xy轴
        drawDaxes(canvas,daxesPaint);

        //开始绘制xy轴坐标
        axispointPaint=daxesPaint;
        drawAxispoint(canvas,axispointPaint);

        //开始绘制折线和坐标点
        brokenLinePaint=axispointPaint;
        brokenLinePaint.setStrokeWidth(5.0f);
        drawbrokenLine(canvas,brokenLinePaint);
    }


   private void  drawDaxes(Canvas canvas,Paint p){
       //开始y绘制坐标系
       canvas.drawLine(widthCriterion,hightCriterion,widthCriterion,hightCriterion*9,p);
       //绘制y角
       canvas.drawLine(widthCriterion-minCriterion,hightCriterion+minCriterion,widthCriterion+2,hightCriterion,p);
       canvas.drawLine(widthCriterion,hightCriterion,widthCriterion+minCriterion-2,hightCriterion+minCriterion,p);
       //开始x绘制坐标系
       canvas.drawLine(widthCriterion-4,hightCriterion*9,widthCriterion*9,hightCriterion*9,p);
       //绘制x角
       canvas.drawLine(widthCriterion*9-minCriterion,hightCriterion*9-minCriterion,widthCriterion*9,hightCriterion*9+2,p);
       canvas.drawLine(widthCriterion*9-minCriterion,hightCriterion*9+minCriterion,widthCriterion*9,hightCriterion*9-2,p);

   }

   private void drawAxispoint(Canvas canvas,Paint p){
       textFont=widthCriterion/5*2;
       Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
       p.setTypeface( font );
       p.setTextSize(textFont);
       for (int i = 1; i <=8 ; i++) {
           String text= String.valueOf(-1+i);
           int stringWidth = (int) p.measureText(text);     //文本长度
           canvas.drawText(text, i*widthCriterion-stringWidth/2, hightCriterion*9+textFont, p);// 画文本
       }
       for (int i = 1; i <=7 ; i++) {
           String text= String.valueOf(i);
           int stringWidth = (int) p.measureText(text);
           //文本长度
           canvas.drawText(text, widthCriterion-textFont, hightCriterion*9-i*hightCriterion+stringWidth/2, p);// 画文本
       }
   }

   private void drawbrokenLine(Canvas canvas,Paint p){
       canvas.drawLine(widthCriterion,hightCriterion*9,widthCriterion*2,hightCriterion*2,p);
       canvas.drawLine(widthCriterion*2,hightCriterion*2,widthCriterion*3,hightCriterion*5,p);
       canvas.drawLine(widthCriterion*3,hightCriterion*5,widthCriterion*4,hightCriterion*7,p);
       canvas.drawLine(widthCriterion*4,hightCriterion*7,widthCriterion*5,hightCriterion*6,p);
       canvas.drawLine(widthCriterion*5,hightCriterion*6,widthCriterion*6,hightCriterion*7,p);
       canvas.drawLine(widthCriterion*6,hightCriterion*7,widthCriterion*7,hightCriterion*2,p);
       canvas.drawLine(widthCriterion*7,hightCriterion*2,widthCriterion*8,hightCriterion*3,p);
       //画折线上的点
       canvas.drawCircle(widthCriterion, hightCriterion*9, 10, p);
       canvas.drawCircle(widthCriterion*2,hightCriterion*2, 10, p);
       canvas.drawCircle(widthCriterion*3,hightCriterion*5, 10, p);
       canvas.drawCircle(widthCriterion*4,hightCriterion*7, 10, p);
       canvas.drawCircle(widthCriterion*5,hightCriterion*6, 10, p);
       canvas.drawCircle(widthCriterion*6,hightCriterion*7, 10, p);
       canvas.drawCircle(widthCriterion*7,hightCriterion*2, 10, p);
       canvas.drawCircle(widthCriterion*8,hightCriterion*3, 10, p);

   }


}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.

下面来简单封装一下

1.首先提供给外界输入数据的方法:

public void setChartdate(String[] xdate, int[] ydate, float[] linedate) {
        this.xdate = xdate;    //x轴坐标
        this.ydate = ydate;    //y轴坐标
        this.linedate = linedate; //坐标点的y轴上的位置
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

2.进行数据为空判断和越界判断

if (xdate.length!=0&&ydate.length!=0&&linedate.length!=0&&xdate.length>=linedate.length){
            if (yMaxdata()>=lineMaxdata()){
                drawAxis(canvas);
            }

        }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

其中yMaxdata(),lineMaxdata()方法作用为取ydate与linedate中的最大值

3.将所有写死的数据与传进来的数据产生联系。

private void drawDaxes(Canvas canvas, Paint p) {
        //开始y绘制坐标系
        canvas.drawLine(widthCriterion, hightCriterion, widthCriterion, hightCriterion * (yCopies - 1), p);
        //绘制y角
        canvas.drawLine(widthCriterion - minCriterion, hightCriterion + minCriterion, widthCriterion + 2, hightCriterion, p);
        canvas.drawLine(widthCriterion, hightCriterion, widthCriterion + minCriterion - 2, hightCriterion + minCriterion, p);
        //开始x绘制坐标系
        canvas.drawLine(widthCriterion - 4, hightCriterion * (yCopies - 1), widthCriterion * (xCopies - 1), hightCriterion * (yCopies - 1), p);
        //绘制x角
        canvas.drawLine(widthCriterion * (xCopies - 1) - minCriterion, hightCriterion * (yCopies - 1) - minCriterion, widthCriterion * (xCopies - 1), hightCriterion * (yCopies - 1) + 2, p);
        canvas.drawLine(widthCriterion * (xCopies - 1) - minCriterion, hightCriterion * (yCopies - 1) + minCriterion, widthCriterion * (xCopies - 1), hightCriterion * (yCopies - 1) - 2, p);

    }

    private void drawAxispoint(Canvas canvas, Paint p) {
        textFont = widthCriterion / 5 * 2;
        Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
        p.setTypeface(font);
        p.setTextSize(textFont);
        //画x轴数据
        for (int i = 0; i < xdate.length; i++) {
            String text = xdate[i];
            int stringWidth = (int) p.measureText(text);     //文本长度
            canvas.drawText(text, (i + 1) * widthCriterion - stringWidth / 2, hightCriterion * (yCopies - 1) + textFont, p);// 画文本
        }
        for (int i = 0; i < ydate.length; i++) {
            String text = String.valueOf(ydate[i]);

            int stringWidth = (int) p.measureText(text);
            //文本长度
            if (i == 0) {
            } else {
                canvas.drawText(text, widthCriterion - textFont-stringWidth, hightCriterion * (yCopies - 1) - i * hightCriterion + stringWidth / 2, p);// 画文本

            }
        }
    }

    private void drawbrokenLine(Canvas canvas, Paint p) {
        float line=(hightCriterion * (yCopies - 1)-hightCriterion*2)/ydate[ydate.length-1];

        for (int i = 0; i <linedate.length; i++) {
            float height=hightCriterion * (yCopies-1)-line*linedate[i];
            if (i!=linedate.length-1){
                float elseheight=hightCriterion * (yCopies-1)-line*linedate[i+1];
                canvas.drawLine(widthCriterion*(i+1),height , widthCriterion * (i+2), elseheight, p);
                canvas.drawCircle(widthCriterion*(i+1), height, 10, p);
            }else{
                float endheight=hightCriterion * (yCopies-1)-line*linedate[linedate.length-1];
                canvas.drawCircle(widthCriterion*(i+1), endheight, 10, p);
            }

        }
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.

现在就可以根据给到的数据动态绘制简单折线图

接下来看效果
在Activity中找到控件后,调用控件的setChartdate()方法;
数据如下:

private String[] xdata={"0","1","2","3","4","5","6","7","8"};
    private int[] yfata={0,10,20,30,40,50,60,70};
    private float[] linedata={5,10,6,30,5,62.5f,6,2,};
  • 1.
  • 2.
  • 3.

传入数据:

linechartview.setChartdate(xdata,yfata,linedata);
  • 1.

效果图如下:

Android用Canvas画一个折线图,并加以简单封装_折线_07

封装后java代码如下

public class LineChartView extends View {

    private int minCriterion;
    private int hightCriterion;
    private int widthCriterion;
    private int canvasHeight;
    private int canvasWidth;
    private int textFont;

    private String[] xdate;
    private int[] ydate;
    private float[] linedate;
    private int xCopies;
    private float yCopies;

    public void setChartdate(String[] xdate, int[] ydate, float[] linedate) {
        this.xdate = xdate;
        this.ydate = ydate;
        this.linedate = linedate;
    }


    public LineChartView(Context context) {
        super(context);
    }

    public LineChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (xdate.length!=0&&ydate.length!=0&&linedate.length!=0&&xdate.length>=linedate.length){
            if (yMaxdata()>=lineMaxdata()){
                drawAxis(canvas);
            }

        }

    }

    //绘制
    private void drawAxis(Canvas canvas) {
        xCopies = xdate.length + 2;
        yCopies = ydate.length + 2;
        Paint daxesPaint, axispointPaint, brokenLinePaint;
        //画布宽度
        canvasWidth = canvas.getWidth();
        //画布高度
        canvasHeight = canvas.getHeight();
        widthCriterion = canvasWidth / xCopies;
        hightCriterion = (int) (canvasHeight / yCopies);
        minCriterion = widthCriterion > hightCriterion ? hightCriterion / 2 : widthCriterion / 2;
        //开始绘制底层背景
        daxesPaint = new Paint();
        daxesPaint.setColor(Color.BLACK);
        daxesPaint.setAntiAlias(true);  //去掉锯齿效果
        daxesPaint.setStrokeWidth(7.0f);
        drawDaxes(canvas, daxesPaint);

        //开始绘制坐标点
        axispointPaint = daxesPaint;
        drawAxispoint(canvas, axispointPaint);

        //开始绘制折线和线上的点
        brokenLinePaint=axispointPaint;
        brokenLinePaint.setStrokeWidth(5.0f);
        drawbrokenLine(canvas,brokenLinePaint);
    }


    private void drawDaxes(Canvas canvas, Paint p) {
        //开始y绘制坐标系
        canvas.drawLine(widthCriterion, hightCriterion, widthCriterion, hightCriterion * (yCopies - 1), p);
        //绘制y角
        canvas.drawLine(widthCriterion - minCriterion, hightCriterion + minCriterion, widthCriterion + 2, hightCriterion, p);
        canvas.drawLine(widthCriterion, hightCriterion, widthCriterion + minCriterion - 2, hightCriterion + minCriterion, p);
        //开始x绘制坐标系
        canvas.drawLine(widthCriterion - 4, hightCriterion * (yCopies - 1), widthCriterion * (xCopies - 1), hightCriterion * (yCopies - 1), p);
        //绘制x角
        canvas.drawLine(widthCriterion * (xCopies - 1) - minCriterion, hightCriterion * (yCopies - 1) - minCriterion, widthCriterion * (xCopies - 1), hightCriterion * (yCopies - 1) + 2, p);
        canvas.drawLine(widthCriterion * (xCopies - 1) - minCriterion, hightCriterion * (yCopies - 1) + minCriterion, widthCriterion * (xCopies - 1), hightCriterion * (yCopies - 1) - 2, p);

    }

    private void drawAxispoint(Canvas canvas, Paint p) {
        textFont = widthCriterion / 5 * 2;
        Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
        p.setTypeface(font);
        p.setTextSize(textFont);
        //画x轴数据
        for (int i = 0; i < xdate.length; i++) {
            String text = xdate[i];
            int stringWidth = (int) p.measureText(text);     //文本长度
            canvas.drawText(text, (i + 1) * widthCriterion - stringWidth / 2, hightCriterion * (yCopies - 1) + textFont, p);// 画文本
        }
        for (int i = 0; i < ydate.length; i++) {
            String text = String.valueOf(ydate[i]);

            int stringWidth = (int) p.measureText(text);
            //文本长度
            if (i == 0) {
            } else {
                canvas.drawText(text, widthCriterion - textFont-stringWidth, hightCriterion * (yCopies - 1) - i * hightCriterion + stringWidth / 2, p);// 画文本

            }
        }
    }

    private void drawbrokenLine(Canvas canvas, Paint p) {
        float line=(hightCriterion * (yCopies - 1)-hightCriterion*2)/ydate[ydate.length-1];

        for (int i = 0; i <linedate.length; i++) {
            float height=hightCriterion * (yCopies-1)-line*linedate[i];
            if (i!=linedate.length-1){
                float elseheight=hightCriterion * (yCopies-1)-line*linedate[i+1];
                canvas.drawLine(widthCriterion*(i+1),height , widthCriterion * (i+2), elseheight, p);
                canvas.drawCircle(widthCriterion*(i+1), height, 10, p);
            }else{
                float endheight=hightCriterion * (yCopies-1)-line*linedate[linedate.length-1];
                canvas.drawCircle(widthCriterion*(i+1), endheight, 10, p);
            }

        }
    }
    private float yMaxdata(){
        float max = 0;
        for (int i = 0; i < ydate.length; i++) {

            if (ydate[i] > max) {
                max = ydate[i];

            }
        }
       return max;
    }

    private float lineMaxdata(){
        float max = 0;
        for (int i = 0; i < linedate.length; i++) {

            if (linedate[i] > max) {
                max = linedate[i];

            }
        }
        return max;
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.

核心:绘制与传入数据产生联系,建议先绘制一次固定的,再自我封装,有利于理解

觉得好的话,点个关注吧!谢谢
如有疑问,欢迎留言。