金融软件里的行情分时图,这是我们最常见的折线图,当然了,折线图的用途并不仅仅局限于此,像一般在一定区间内,为了更好的能显示出幅度的变化,那么用折线图来展示无疑是最符合效果的,当然了,网上也有很多的第三方开源,这篇文章呢,对开源的不做过多描述,想要了解请关注后续文章,好了,废话不多说,让我们从0来一步步绘制折线图吧。
先来看一下我们最终要实现的效果:
很简单的一个空气质量折线图,俗话说,磨刀不误砍柴功,我们可以简单的分析一下,这个折线图主要包含了那几块,上面的标题可以做为一块,xy坐标轴是一块,折线是一块,简单的分为三块之后,代码我们就可以一块一块的去写。
定义一个类继承于View,实现其构造方法,先初始化我们需要的东西,背景设置偏黑色,初始化画笔。
private void initView() {
setBackgroundColor(Color.parseColor("#222222"));
mPaint = new Paint();
}
在onDraw()方法里绘制标题:
/**
* 绘制标题
*/
private void canvasTitle(Canvas canvas) {
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(50);
mPaint.setTypeface(blodFont);
canvas.drawText("帝都空气质量趋势图(author:AbnerMing)", 100, 50, mPaint);
}
setTypeface()是用来设置字体,这里我设置的是,宋体加粗
Typeface blodFont = Typeface.create("宋体", Typeface.BOLD);
在onDraw()方法里绘制XY轴:
为了使整体看起来稍稍美观,我们绘制的时候,尽量与上下左右保持一定的距离,这里我设置的是距离底部为this.getBottom()-100,距离左边为100,代码如下:
int marginBottom = this.getBottom() - 100;
int marginLeft = 100;
初始化XY轴:
//初始化X轴
mPaint.setColor(Color.WHITE);
canvas.drawLine(marginLeft, marginLeft, marginLeft, marginBottom, mPaint);
//初始化Y轴
mPaint.setStrokeWidth(6);
canvas.drawLine(marginLeft, marginBottom, this.getRight() - 20, marginBottom, mPaint);
XY轴绘制好之后,紧接着我们绘制时间轴,时间轴,这里我分成了5份,每份为5个小时,最后一份为4个小时,一份的宽度计算方式为:屏幕的宽度-距离右边的宽度-距离左边的宽度/5,代码如下:
int xWidth = (this.getRight() - 20 - marginLeft) / 5;
起始位置呢,就是距离左边的距离:
int xLine = marginLeft;//起始位置
每一个时间点,都是逐个增加一份的宽度,这里我们new一个Integer数组来存储:
Integer[] xPoint = new Integer[5];
for (int a = 0; a < 5; a++) {
xLine += xWidth;
xPoint[a] = xLine;
}
xPoint就是各个时间点的X轴坐标,显然Y轴是不变的,那么我们就可以如下绘制;
for (int i = 0; i < xPoint.length; i++) {
mPaint.setColor(Color.parseColor("#FF00FF"));
mPaint.setTextSize(40);
mPaint.setTypeface(font);
mPaint.setTextAlign(Paint.Align.RIGHT);
if (i == 0) {
canvas.drawText("0", marginLeft,
marginBottom + 50, mPaint);
canvas.drawText(times[i], xPoint[i],
marginBottom + 50, mPaint);
} else {
canvas.drawText(times[i], xPoint[i],
marginBottom + 50, mPaint);
}
}
times是自己定义的时间数组:
private String[] times = {"5:00", "10:00", "15:00", "20:00", "24:00"};
X轴的时间绘制好后,接着我们来绘制Y轴,其实Y轴的思路和X轴一样,也是分成5份,每份的计算方式为:屏幕的高度-距离底部的距离-距离上部的距离/5,代码如下;
int yHeight = (marginBottom - marginLeft) / 5;
由于5份每份的颜色值不一样,所以我们要逐一进行处理:
for (int i = 0; i < xPoint.length; i++) {
mPaint.setStrokeWidth(6);
int startY = marginBottom - yHeight * (i + 1);
int endY = marginBottom - yHeight * i;
switch (i) {
case 0:
mPaint.setColor(Color.GREEN);
break;
case 1:
mPaint.setColor(Color.YELLOW);
break;
case 2:
mPaint.setColor(0xFFFF7E00);
break;
case 3:
mPaint.setColor(Color.RED);
break;
case 4:
mPaint.setColor(0xFF8E1752);
break;
}
//绘制颜色线
canvas.drawLine(marginLeft, startY,
marginLeft, endY, mPaint);
//绘制空气污染值
canvas.drawText(atmosphereNum[i] + "", marginLeft - 20,
startY, mPaint);
//绘制空气污染等级
canvas.drawText(atmosphere[i], marginLeft - 20,
endY - yHeight / 2, mPaint);
}
atmosphere是自己定义的污染值等级数组,atmosphere是自己定义的污染值数组:
private String[] atmosphere = {"优", "好", "良", "中", "差"};
private int[] atmosphereNum = {100, 200, 300, 400, 500};
再来看最后一块,折线图的绘制。其实每个点就是一个坐标,绘制之前我们先把需要的数据整理一下:
private float[] broken = {0f, 30f, 75f, 160f, 66f, 170f, 80f, 120f,130f,150f,138f,180f,200f,
220f,300f,235f,245f,260f,210f,270f,290f,270f,270f,250f,210f,180f,260f,280f,320f};
private int[] brokenTimes = {0, 5, 10, 15, 20, 25, 30, 35,40,45,50,55,60,
65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140};
private Paint mPaint;
broken数组,是空气污染值,下面的brokenTimes是时间点,我是这样做的,X轴是24小时,共有1440分钟,我分成了10分钟一个点,也就是最多有144个点,brokenTimes里的数值都是增的,毕竟时间走着走着不可能变小,broken数组和brokenTimes数组的长度一定要一样大,因为,各个对应的值就是xy值。
纵轴是500个值,所以纵轴刻度值等于屏幕的高度-距离底部的距离-距离上部的距离/500,代码如下:
float brokenSizeY = (marginBottom - marginLeft) / 500;//得到纵轴刻度值
横轴刻度值等于屏幕的宽度-距离左边的距离-距离右边的距离/144,代码如下:
float brokenSizeX = (this.getRight() - 20 - marginLeft) / 144;
绘制如下:
float lastX = brokenTimes[0] * brokenSizeX + marginLeft, lastY = marginBottom - broken[0] * brokenSizeY;
for (int a = 0; a < broken.length; a++) {
float height = marginBottom - broken[a] * brokenSizeY;
float width = brokenTimes[a] * brokenSizeX + marginLeft;
canvas.drawCircle(width, height, 10, mPaint);
canvas.drawLine(lastX, lastY, width, height, mPaint);
lastX = width;
lastY = height;
}
lastX是记录上一个X点,lastY是记录上一个Y点。
经过以上的代码,我们就可以绘制出文章刚开始的图片效果了,具体使用,也特别简单,哪里需要用,就在layout里调用就可以了:
<com.ming.abner.chartline.BrokenLineView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>