先看一下效果图
![]() |
![]() |
![]() |
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);
drawDaxes方法如下:
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);
}
效果如下:
//开始绘制xy轴坐标
axispointPaint=daxesPaint;
drawAxispoint(canvas,axispointPaint);
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);// 画文本
}
}
效果图如下:
//开始绘制折线和坐标点
brokenLinePaint=axispointPaint;
brokenLinePaint.setStrokeWidth(5.0f);
drawbrokenLine(canvas,brokenLinePaint);
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);
}
效果图如下:
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.首先提供给外界输入数据的方法:
public void setChartdate(String[] xdate, int[] ydate, float[] linedate) {
this.xdate = xdate; //x轴坐标
this.ydate = ydate; //y轴坐标
this.linedate = linedate; //坐标点的y轴上的位置
}
2.进行数据为空判断和越界判断
if (xdate.length!=0&&ydate.length!=0&&linedate.length!=0&&xdate.length>=linedate.length){
if (yMaxdata()>=lineMaxdata()){
drawAxis(canvas);
}
}
其中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);
}
}
}
现在就可以根据给到的数据动态绘制简单折线图
接下来看效果
在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,};
传入数据:
linechartview.setChartdate(xdata,yfata,linedata);
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;
}
}
核心:绘制与传入数据产生联系,建议先绘制一次固定的,再自我封装,有利于理解
觉得好的话,点个关注吧!谢谢
如有疑问,欢迎留言。