昨天晚上跟朋友聊天,聊到绘制折线,然后多画了几笔,画了个折线图。(老规矩后面有源码)
先看一下效果图
|
view宽高设置为正方形 |
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.
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.
效果如下:

2.再绘制x,y轴坐标
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.
效果图如下:

3.最后绘制折线和坐标点
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.
效果图如下:

固定的折线图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.首先提供给外界输入数据的方法:
2.进行数据为空判断和越界判断
其中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()方法;
数据如下:
传入数据:
效果图如下:

封装后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.
核心:绘制与传入数据产生联系,建议先绘制一次固定的,再自我封装,有利于理解
觉得好的话,点个关注吧!谢谢
如有疑问,欢迎留言。



1651

被折叠的 条评论
为什么被折叠?



