首页 > 代码库 > Android - 折线图

Android - 折线图

使用Android的canvas,画折线图:代码为:

package spt.view;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.DashPathEffect;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathEffect;import android.util.Log;import android.view.View;/** * 为了扩展不同分辨率手机的兼容性,百分比和一些重要变量设置为final,其他可变变量设置为成员变量. *  * @author Administrator *  */@SuppressLint("DrawAllocation")public class BrokenLineView extends View {	// 计算相对比例时,均使用边距margin为依照(值与比例结果成反比).	// 画轴线时,箭头所占比例.	private static final int ARROW_PECENT = 10;	// x,y轴坐标点文字的比例.	private static final int X_TEXT_PECENT = 10;	private static final int Y_TEXT_PECENT = 10;	// 标题文字的比例.	private static final int TITLE_TEXT_PECENT = 5;	// 默认坐标轴值.	private static final String[] X_LABLE = { "a", "b", "c", "d", "e", "f", "g" };	private static final String[] Y_LABLE = { "0", "50", "100", "150", "200",			"250", "300" };	// 数据点圆的半径.	private static final int dataRadius = 10;	// x,y轴坐标点数字的位置偏离轴线的距离.	private int xTextDistanceAxis = 20;	private int yTextDistanceAxis = 30;	// 数据点数值文字相对于数据点的高度值.	private int dataTextAboveCircle = 25;	// 边距(也不能为final,因为可能用户可能根据不同条件设置不同间距.	private int margin = 100;	// X,Y轴的单位长度	private int xScale = 20;	private int yScale = 20;	// 标题的高度.	private String title;	// 标题距离最顶行线的y距离.	private int titleHeight = 20;	// 原点坐标	private int x0Point;	private int y0Point;	// X,Y轴上面的显示文字	private String[] xLabel = null;	private String[] yLabel = null;	// 曲线数据	private int[] data = http://www.mamicode.com/null;"data cannot null:");		this.data = http://www.mamicode.com/data;"间距不能为负数:" + margin);		this.margin = margin;	}	@Override	protected void onDraw(Canvas canvas) {		canvas.drawColor(Color.BLACK); // 背景色.		Paint p = new Paint();		p.setStyle(Paint.Style.STROKE); // 设置轴线的的外框的样式“空心”(STROKE).		p.setAntiAlias(true); // 抗锯齿		p.setColor(Color.WHITE);		p.setStrokeWidth(2); // 设置轴线的的外框的宽度.		init();		drawYAxis(canvas, p);		drawXAxis(canvas, p);		drawHorizontalLine(canvas);		drawData(canvas);	}	// x向线	private void drawHorizontalLine(Canvas canvas) {		Paint paint = new Paint();		paint.setStyle(Paint.Style.STROKE);		paint.setColor(Color.GRAY);		Path path = new Path();		// 先画长度为1的实线,然后长度为10的空白,再画长度为1实线,再画长度为10的空白;最后一个是是偏移量,可不理会.		PathEffect effects = new DashPathEffect(new float[] { 1, 10, 1, 10 }, 1);		paint.setPathEffect(effects);		for (int i = 1; (y0Point - i * yScale) >= margin; i++) {			int startX = x0Point;			int startY = y0Point - i * yScale;			int stopX = x0Point + (xLabel.length - 1) * xScale;			path.moveTo(startX, startY);			path.lineTo(stopX, startY);			paint.setColor(Color.DKGRAY);			canvas.drawPath(path, paint);		}	}	/**	 * 画y轴线	 * 	 * @param canvas	 * @param p	 */	private void drawYAxis(Canvas canvas, Paint p) {		// y轴.		canvas.drawLine(x0Point, y0Point, margin, margin, p);		// y轴箭头的左部分.		canvas.drawLine(x0Point, margin, x0Point - x0Point / ARROW_PECENT,				margin + margin / ARROW_PECENT, p);		// y轴箭头的右部分.		canvas.drawLine(x0Point, margin, x0Point + x0Point / ARROW_PECENT,				margin + margin / ARROW_PECENT, p);	}	/**	 * 画x轴线.	 * 	 * @param canvas	 * @param p	 */	private void drawXAxis(Canvas canvas, Paint p) {		// x轴.		canvas.drawLine(x0Point, y0Point, getWidth() - margin, y0Point, p);		// x轴箭头的上部分.		canvas.drawLine(getWidth() - margin, y0Point, getWidth() - margin				- margin / ARROW_PECENT, y0Point - margin / ARROW_PECENT, p);		// x轴箭头的下部分.		canvas.drawLine(getWidth() - margin, y0Point, getWidth() - margin				- margin / ARROW_PECENT, y0Point + margin / ARROW_PECENT, p);	}	// 画数据	private void drawData(Canvas canvas) {		Paint p = new Paint();		p.setAntiAlias(true); // 抗锯齿.		p.setColor(Color.RED);		p.setTextSize(margin / X_TEXT_PECENT);		for (int x = 0; x < data.length; x++) {			int startX = x0Point + x * xScale;			// 轴坐标点文字的显示.			canvas.drawText(xLabel[x], startX, y0Point + xTextDistanceAxis, p);			// 数据点的圆.			canvas.drawCircle(startX, calY(data[x]), dataRadius, p);			// 在数据点上标数据值.			canvas.drawText(data[x] + "", startX, calY(data[x]) + dataRadius					- dataTextAboveCircle, p);			// 在数据点圆间画变化线.			// 画线时,最后数据点不执行操作.			if (x != data.length - 1)				canvas.drawLine(startX, calY(data[x]), startX + xScale,						calY(data[x + 1]), p);		} // for x.		// 画y轴坐标点文字.		Paint py = new Paint();		py.setAntiAlias(true); // 抗锯齿.		py.setColor(Color.RED);		py.setTextSize(margin / Y_TEXT_PECENT);		for (int y = 0; y < yLabel.length; y++) {			int startY = y0Point - y * yScale;			// y轴坐标点文字的显示.			canvas.drawText(yLabel[y], x0Point - yTextDistanceAxis, startY, py);		} // for y.		// 画标题.		Paint pTitle = new Paint();		pTitle.setAntiAlias(true); // 抗锯齿.		pTitle.setColor(Color.RED);		pTitle.setTextSize(margin / TITLE_TEXT_PECENT);		// 通过Paint.measureText计算标题长度的像素,进而将标题水平居中.		canvas.drawText(title, (getWidth() - pTitle.measureText(title)) / 2,				margin - titleHeight, pTitle);	}	/**	 * 计算数据值在坐标系中y的位置.	 * 	 * @param y	 * @return	 */	private int calY(int y) {		int y0 = 0;		int y1 = 0;		try {			y0 = Integer.parseInt(yLabel[0]);			y1 = Integer.parseInt(yLabel[1]);			return y0Point - ((y - y0) * yScale / (y1 - y0));		} catch (NumberFormatException e) {			Log.d("sysout", "y轴label必须是数字:" + e.getMessage());			return -1;		}	}}

 然后在Activity中调用即可:

@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);				//test:		int[] data = http://www.mamicode.com/{ 0, 50, 51, 78, 200, 121, 31 };"最近一周AQI变化图";		setContentView(new BrokenLineView(this, title, null, null, data));		initView();	}

 

Android - 折线图