Android自定义组件系列——Canvas绘制折线图

Posted lxq_xsyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义组件系列——Canvas绘制折线图相关的知识,希望对你有一定的参考价值。

有时候我们在项目中会遇到使用折线图等图形,android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas绘制折线图。先看看绘制的效果:

实现原理很简单,我就直接给出代码:

package com.example.testcanvasdraw;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View
	private int XPoint = 60;
	private int YPoint = 260;
	private int XScale = 8;  //刻度长度
	private int YScale = 40;
	private int XLength = 380;
	private int YLength = 240;
	
	private int MaxDataSize = XLength / XScale;
	
	private List<Integer> data = new ArrayList<Integer>();
	

	
	private String[] YLabel = new String[YLength / YScale];
	
	private Handler handler = new Handler()
		public void handleMessage(Message msg) 
			if(msg.what == 0x1234)
				MyView.this.invalidate();
			
		;
	;
	public MyView(Context context, AttributeSet attrs) 
		super(context, attrs);
		for(int i=0; i<YLabel.length; i++)
			YLabel[i] = (i + 1) + "M/s";
		
		
		new Thread(new Runnable() 
			
			@Override
			public void run() 
				while(true)
					try 
						Thread.sleep(1000);
					 catch (InterruptedException e) 
						e.printStackTrace();
					
					if(data.size() >= MaxDataSize)
						data.remove(0);
					
					data.add(new Random().nextInt(4) + 1);
					handler.sendEmptyMessage(0x1234);
				
			
		).start();
	
	
	@Override
	protected void onDraw(Canvas canvas) 
		super.onDraw(canvas);
		Paint paint = new Paint();
		paint.setStyle(Paint.Style.STROKE);
		paint.setAntiAlias(true); //去锯齿
		paint.setColor(Color.BLUE);
		
		//画Y轴
		canvas.drawLine(XPoint, YPoint - YLength, XPoint, YPoint, paint);
		
		//Y轴箭头
		canvas.drawLine(XPoint, YPoint - YLength, XPoint - 3, YPoint-YLength + 6, paint);  //箭头
	    canvas.drawLine(XPoint, YPoint - YLength, XPoint + 3, YPoint-YLength + 6 ,paint);
	    
	    //添加刻度和文字
	    for(int i=0; i * YScale < YLength; i++) 
	    	canvas.drawLine(XPoint, YPoint - i * YScale, XPoint + 5, YPoint - i * YScale, paint);  //刻度
	    	
	    	canvas.drawText(YLabel[i], XPoint - 50, YPoint - i * YScale, paint);//文字
	    
		
		//画X轴
		canvas.drawLine(XPoint, YPoint, XPoint + XLength, YPoint, paint);
		System.out.println("Data.size = " + data.size());
		if(data.size() > 1)
			for(int i=1; i<data.size(); i++)
			    canvas.drawLine(XPoint + (i-1) * XScale, YPoint - data.get(i-1) * YScale, 
			    		XPoint + i * XScale, YPoint - data.get(i) * YScale, paint);
			
		
	

上面绘制折线部分我们还有一种方式同样可以实现:

		if(data.size() > 1)
			Path path = new Path();
			path.moveTo(XPoint, YPoint - data.get(0) * YScale);
			for(int i=1; i<data.size(); i++)
				path.lineTo(XPoint + i * XScale, YPoint - data.get(i) * YScale);
			
			canvas.drawPath(path, paint);
		
下面我们将上面代码修改,让折线下面的区域颜色填充

package com.example.testcanvasdraw;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
/**
 * 
 * @author 阳光小强
 * http://blog.csdn.net/dawanganban
 *
 */
public class MyView extends View 
	private int XPoint = 60;
	private int YPoint = 260;
	private int XScale = 8; // 刻度长度
	private int YScale = 40;
	private int XLength = 380;
	private int YLength = 240;

	private int MaxDataSize = XLength / XScale;

	private List<Integer> data = new ArrayList<Integer>();

	private String[] YLabel = new String[YLength / YScale];

	private Handler handler = new Handler() 
		public void handleMessage(Message msg) 
			if (msg.what == 0x1234) 
				MyView.this.invalidate();
			
		;
	;

	public MyView(Context context, AttributeSet attrs) 
		super(context, attrs);
		for (int i = 0; i < YLabel.length; i++) 
			YLabel[i] = (i + 1) + "M/s";
		

		new Thread(new Runnable() 

			@Override
			public void run() 
				while (true) 
					try 
						Thread.sleep(1000);
					 catch (InterruptedException e) 
						e.printStackTrace();
					
					if (data.size() >= MaxDataSize) 
						data.remove(0);
					
					data.add(new Random().nextInt(4) + 1);
					handler.sendEmptyMessage(0x1234);
				
			
		).start();
	

	@Override
	protected void onDraw(Canvas canvas) 
		super.onDraw(canvas);
		Paint paint = new Paint();
		paint.setStyle(Paint.Style.STROKE);
		paint.setAntiAlias(true); // 去锯齿
		paint.setColor(Color.BLUE);

		// 画Y轴
		canvas.drawLine(XPoint, YPoint - YLength, XPoint, YPoint, paint);

		// Y轴箭头
		canvas.drawLine(XPoint, YPoint - YLength, XPoint - 3, YPoint - YLength
				+ 6, paint); // 箭头
		canvas.drawLine(XPoint, YPoint - YLength, XPoint + 3, YPoint - YLength
				+ 6, paint);

		// 添加刻度和文字
		for (int i = 0; i * YScale < YLength; i++) 
			canvas.drawLine(XPoint, YPoint - i * YScale, XPoint + 5, YPoint - i
					* YScale, paint); // 刻度

			canvas.drawText(YLabel[i], XPoint - 50, YPoint - i * YScale, paint);// 文字
		

		// 画X轴
		canvas.drawLine(XPoint, YPoint, XPoint + XLength, YPoint, paint);

		// 绘折线
		/*
		 * if(data.size() > 1) for(int i=1; i<data.size(); i++)
		 * canvas.drawLine(XPoint + (i-1) * XScale, YPoint - data.get(i-1) *
		 * YScale, XPoint + i * XScale, YPoint - data.get(i) * YScale, paint); 
		 * 
		 */
		paint.setStyle(Paint.Style.FILL);
		if (data.size() > 1) 
			Path path = new Path();
			path.moveTo(XPoint, YPoint);
			for (int i = 0; i < data.size(); i++) 
				path.lineTo(XPoint + i * XScale, YPoint - data.get(i) * YScale);
			
			path.lineTo(XPoint + (data.size() - 1) * XScale, YPoint);
			canvas.drawPath(path, paint);
		
	

上面的效果有时候还是达不到我们的要求,我们将代码修改后效果如下:

package com.example.testcanvasdraw;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

/**
 * 
 * @author 阳光小强 http://blog.csdn.net/dawanganban
 * 
 */
public class MyView extends View 
	private int XPoint = 60;
	private int YPoint = 260;
	private int XScale = 8; // 刻度长度
	private int YScale = 40;
	private int XLength = 380;
	private int YLength = 240;

	private int MaxDataSize = XLength / XScale;

	private List<Integer> data = new ArrayList<Integer>();

	private String[] YLabel = new String[YLength / YScale];

	private Handler handler = new Handler() 
		public void handleMessage(Message msg) 
			if (msg.what == 0x1234) 
				MyView.this.invalidate();
			
		;
	;

	public MyView(Context context, AttributeSet attrs) 
		super(context, attrs);
		for (int i = 0; i < YLabel.length; i++) 
			YLabel[i] = (i + 1) + "M/s";
		

		new Thread(new Runnable() 

			@Override
			public void run() 
				while (true) 
					try 
						Thread.sleep(1000);
					 catch (InterruptedException e) 
						e.printStackTrace();
					
					if (data.size() >= MaxDataSize) 
						data.remove(0);
					
					data.add(new Random().nextInt(4) + 1);
					handler.sendEmptyMessage(0x1234);
				
			
		).start();
	

	@Override
	protected void onDraw(Canvas canvas) 
		super.onDraw(canvas);
		Paint paint = new Paint();
		paint.setStyle(Paint.Style.STROKE);
		paint.setAntiAlias(true); // 去锯齿
		paint.setColor(Color.BLUE);

		// 画Y轴
		canvas.drawLine(XPoint, YPoint - YLength, XPoint, YPoint, paint);

		// Y轴箭头
		canvas.drawLine(XPoint, YPoint - YLength, XPoint - 3, YPoint - YLength
				+ 6, paint); // 箭头
		canvas.drawLine(XPoint, YPoint - YLength, XPoint + 3, YPoint - YLength
				+ 6, paint);

		// 添加刻度和文字
		for (int i = 0; i * YScale < YLength; i++) 
			canvas.drawLine(XPoint, YPoint - i * YScale, XPoint + 5, YPoint - i
					* YScale, paint); // 刻度

			canvas.drawText(YLabel[i], XPoint - 50, YPoint - i * YScale, paint);// 文字
		

		// 画X轴
		canvas.drawLine(XPoint, YPoint, XPoint + XLength, YPoint, paint);

		// 绘折线
		/*
		 * if(data.size() > 1) for(int i=1; i<data.size(); i++)
		 * canvas.drawLine(XPoint + (i-1) * XScale, YPoint - data.get(i-1) *
		 * YScale, XPoint + i * XScale, YPoint - data.get(i) * YScale, paint); 
		 * 
		 */
		paint.setColor(Color.RED);
		paint.setStrokeWidth(5);

		Paint paint2 = new Paint();
		paint2.setColor(Color.BLUE);
		paint2.setStyle(Paint.Style.FILL);
		if (data.size() > 1) 
			Path path = new Path();
			Path path2 = new Path();
			path.moveTo(XPoint, YPoint - data.get(0) * YScale);
			path2.moveTo(XPoint, YPoint);
			for (int i = 0; i < data.size(); i++) 
				path.lineTo(XPoint + i * XScale, YPoint - data.get(i) * YScale);
				path2.lineTo(XPoint + i * XScale, YPoint - data.get(i) * YScale);
			
			path2.lineTo(XPoint + (data.size() - 1) * XScale, YPoint);
			canvas.drawPath(path, paint);
			canvas.drawPath(path2, paint2);
		
	

感谢你对“阳光小强"的关注,我的另一篇博文很荣幸参加了CSDN举办的博文大赛,如果你觉的小强的博文对你有帮助,请为小强投上你宝贵的一票,投票地址http://vote.blog.csdn.net/Article/Details?articleid=30101091


以上是关于Android自定义组件系列——Canvas绘制折线图的主要内容,如果未能解决你的问题,请参考以下文章

android帧的绘制过程以及fps的获取

Android自定义View(3) 《Canvas绘制简单的图形》

Android自定义View - 仿支付宝月账单折线图

Android自定义绘制1-1 Plus

Android自定义绘制1-1 Plus

Android自定义 View 系列- 绘制流程