Android 自定义view绘制折线图

来源:互联网 发布:lambda表达式java 编辑:程序博客网 时间:2024/06/05 16:37

个人记录使用
新建类,继承view
重写ondraw方法;
带2组Y轴坐标(数据超过一定值则用大的那组)
同步更新的X轴坐标
Y轴有小横线标。
X轴和数据点都有圆点。
懒得截图了。效果就是普通的折线图。(不过丑了点)

    private Paint STROKEpaint = new Paint();    private Paint FILLpaint = new Paint();    private LinkedList<Float> ls = new LinkedList<Float>();    private String[] str = { "    0", "  20", "  40", "  60", "  80" };    private String[] strbig = { "    0", "200", "400", "600", "800" };    float TH, TX, YT, XT, BFBY;    private LinkedList<String> sj = new LinkedList<String>();    @Override    protected void onDraw(Canvas canvas) {        TH = getHeight() - 20;//为高度上下做预留,方便文字的显示        TX = getWidth() - 20;//为宽度左右做预留,方便文字的显示        STROKEpaint.setAntiAlias(true);//抗锯齿,关了线很丑        STROKEpaint.setStyle(Paint.Style.STROKE);//设置画笔为空心        STROKEpaint.setStrokeWidth(1);//设置空心线宽        STROKEpaint.setTextSize(12);//设置字体大小        FILLpaint.setAntiAlias(true);        FILLpaint.setStyle(Paint.Style.FILL);//设置画笔为实心        FILLpaint.setStrokeWidth(1);        canvas.drawLine(20, 0, 20, getHeight(), STROKEpaint);//画Y轴线        canvas.drawLine(0, TH, getWidth(), TH, STROKEpaint);//画X轴线        YT = (float) (TH / 5.0);//Y轴有5段长,0~100,这里先把坐标轴的一份分出来        XT = (float) (TX / 8.0);//同理,不过X轴分为7段        for (int i = 0; i < ls.size(); i++) {            float value = ls.get(i);            if (value > 100) {                BFBY = (float) (TH / 1000.0);//计算坐标轴百分比,遍历列表里有没有超过100的数据,如果有就用1000的百分比;                break;            } else {                BFBY = (float) (TH / 100.0);            }        }        for (int i = 0; i < str.length; i++) {            if (BFBY < 1) {                canvas.drawText(strbig[i], 0, TH - (YT * i), FILLpaint);//如果是1000的百分比,那切出来的1份肯定很小(比1还小),所以这里画这里画Y轴坐标点就用1000尺度的那个数组。            } else {                canvas.drawText(str[i], 0, TH - (YT * i), FILLpaint);                //没超过100就画这个            }        }        for (int i = 0; i < 6; i++) {            canvas.drawLine(20, TH - (YT * i), 25, TH - (YT * i), STROKEpaint);//Y轴坐标点旁边的小横线(25改成总宽度其实就变成网格线里的横线了),Y轴分5段,自然就有6条小横线。        }        for (int i = 0; i < 7; i++) {            canvas.drawCircle((XT * (i + 1)) + 20, TH, 2, FILLpaint);//X轴上的小圆点,按照一开始就算好的单份坐标*对应的数就好了,记得加上预留20的宽度。        }        Path path = new Path();//定义一条线,其实这种频繁调用的方法里不应该new东西,但写外面稍微烦了点(不能只定义一条),所以就写里面了。        for (int i = 0; i < ls.size(); i++) {            float value = ls.get(i);//从数据源拿数据            String show = sj.get(i);//从数据源拿X轴上对应显示的数据            if (i == 0) {                path.moveTo(TX - (XT * (i + 1)) + 20, TH - (value * BFBY));//第一次先用move,移动到第一个点。            } else {                path.lineTo(TX - (XT * (i + 1)) + 20, TH - (value * BFBY));//按着次数往下画,数据只在Y轴变化,X轴总归是那些点。            }            canvas.drawCircle(TX - (XT * (i + 1)) + 20, TH - (value * BFBY), 2,FILLpaint);//给数据转折的地方画点(X轴总是那些点不变,Y轴跟着变而已)            canvas.drawText(show, TX - (XT * (i + 1)) + 15, TH + 10, FILLpaint);//给X轴画上对应的数据标准(01 02~~)之类的。        }        canvas.drawPath(path, STROKEpaint);//记得在for循环外面再把线画出来。。。不然会7条线叠起来,很难看。    }    public void start(LinkedList<Float> ls, LinkedList<String> sj) {        this.ls = ls;//传数据        this.sj = sj;        postInvalidate();//更新界面,每次获取到新数据就触发ondraw重绘。    }

问题很多:
没有管理好ondraw画的东西(很多东西其实可以画一次,比如XY轴,但现在每次其实都重画了,加大的负担);
画图的计算方式,虽然我自己看得懂,但一眼看上去也很懵逼,有时候还得调(加加减减什么的);

注意点:
第一步,一定要给预留,不然XY轴的字没地方写了。
第二步,画布是0,0是从左上角开始的,所以其实你画一张正着的图表,都是反着来的!(但只要相减一下就好,折线是从左往右刷新还是从右往左刷新其实都是减一下就好)
第三步,要画一个能显示75.3这种数据的,每份坐标要很小,我现在是每份是1(总数100,我就/了100份),所以只能显示精确到个位的数,如果一份坐标点只有0.1,那自然可以精确到小数位