`
轻指飞扬
  • 浏览: 32727 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类

android自定义控件之折线图

阅读更多

最近在学着做android自定义控件,为熟练Canvas与Paint的使用方法而写了个折线图控件。效果如下:

图中的X轴刻度数、Y轴的刻度数、折现数、以及折现数据都做了参数供调用者指定。废话不多了,直接上控件代码

 

package com.example.customwidget;

import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;

/**
 * 折线图控件
 * 
 * @author 轻指飞扬
 * @version 1.0
 */
public class LineChart extends View {

	Typeface font = Typeface.create("宋体", Typeface.NORMAL);
	Typeface blodFont = Typeface.create("宋体", Typeface.BOLD);

	private CharInfo charInfo;//图表信息
	private List<LineInfo> lineInfos;//折线信息

	public LineChart(Context context) {
		super(context);
	}

	public LineChart(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public LineChart(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		Paint paint = new Paint();
		paint.setColor(Color.WHITE);
		paint.setTextSize(20);
		paint.setTypeface(blodFont);
		canvas.drawText(charInfo.getTitle(), 100, 20, paint);
		// canvas.drawText("最近24小时空气质量指数", 100, 20, paint);

		int ySpliteNum = charInfo.getyScaleNum();
		int xSpliteNum = charInfo.getxScaleNum();
		// int ySpliteNum = 6;
		// int xSpliteNum = 6;

		// X轴信息
		int xLineXStartCoord = this.getLeft() + 12;
		int xLineXEndCoord = this.getRight() - 50;
		int xLineYStartCoord = this.getBottom() - 70;
		int xLineYEndCoord = xLineYStartCoord;
		int xLineLength = xLineXEndCoord - xLineXStartCoord;

		// Y轴信息
		int yLineXStartCoord = xLineXStartCoord;
		int yLineXEndCoord = xLineXStartCoord;
		int yLineYStartCoord = xLineYStartCoord;
		int yLineYEndCoord = this.getTop() + 50;
		int yLineLength = yLineYStartCoord > yLineYEndCoord == true ? yLineYStartCoord
				- yLineYEndCoord
				: yLineYEndCoord - yLineYStartCoord;

		// 画坐标轴
		paint.setStrokeWidth(2);
		canvas.drawLine(xLineXStartCoord, xLineYStartCoord, xLineXEndCoord,
				xLineYEndCoord, paint);
		canvas.drawLine(yLineXStartCoord, yLineYStartCoord, yLineXEndCoord,
				yLineYEndCoord, paint);

		// 画X轴(时间轴)刻度
		paint.setColor(0xCCCCCCFF);
		int scale = 5;
		Integer[] xPoint = new Integer[xSpliteNum];
		int xStep = xLineLength / xSpliteNum;
		int xLine = xLineXStartCoord;
		for (int i = 0; i < xSpliteNum; i++) {
			xLine += xStep;
			xPoint[i] = xLine;
			canvas.drawLine(xLine, xLineYStartCoord + scale, xLine,
					xLineYEndCoord - scale, paint);
		}
		String[] xScaleDownLabel = charInfo.getxScaleDownLable();
		for (int i = 0; i < xPoint.length; i++) {
			paint.setColor(Color.WHITE);
			paint.setTextSize(14);
			paint.setTypeface(font);
			paint.setTextAlign(Align.RIGHT);
			if (i == 0) {
				canvas.drawText(xScaleDownLabel[i], yLineXStartCoord,
						xLineYStartCoord + 15, paint);
				canvas.drawText(xScaleDownLabel[i + 1], xPoint[i],
						xLineYStartCoord + 15, paint);
			} else {
				canvas.drawText(xScaleDownLabel[i + 1], xPoint[i],
						xLineYStartCoord + 15, paint);
			}
		}

		String[] yScaleLeftLabel = charInfo.getyScaleLeftLable();
		String[] yScaleRightLabel = charInfo.getyScaleRightLable();
		// Y轴划分
		Integer[] yPoint = new Integer[ySpliteNum];
		int yStep = yLineLength / ySpliteNum;
		int yLine = yLineYStartCoord;
		for (int i = 0; i < ySpliteNum; i++) {
			if (i == ySpliteNum - 1) {
				yLine = yLineYEndCoord;
			} else {
				yLine -= yStep;
			}
			yPoint[i] = yLine;
			canvas.drawLine(yLineXStartCoord, yLine, yLineXStartCoord
					+ xLineLength, yLine, paint);
		}

		// Y轴色块、数字
		for (int i = 0; i < yPoint.length; i++) {
			paint.setStrokeWidth(6);
			switch (i) {
			case 0:
				paint.setColor(Color.GREEN);
				canvas.drawLine(yLineXStartCoord, xLineYStartCoord,
						yLineXStartCoord, yPoint[i], paint);

				paint.setColor(Color.WHITE);
				paint.setTextSize(14);
				paint.setTypeface(font);
				paint.setTextAlign(Align.RIGHT);
				canvas.drawText("0", yLineXStartCoord - 6, xLineYStartCoord,
						paint);
				break;
			case 1:
				paint.setColor(Color.YELLOW);
				canvas.drawLine(yLineXStartCoord, yPoint[i - 1],
						yLineXStartCoord, yPoint[i], paint);
				break;
			case 2:
				paint.setColor(0xFFFF7E00);
				canvas.drawLine(yLineXStartCoord, yPoint[i - 1],
						yLineXStartCoord, yPoint[i], paint);
				break;
			case 3:
				paint.setColor(Color.RED);
				canvas.drawLine(yLineXStartCoord, yPoint[i - 1],
						yLineXStartCoord, yPoint[i], paint);
				break;
			case 4:
				paint.setColor(0xFF8E1752);
				canvas.drawLine(yLineXStartCoord, yPoint[i - 1],
						yLineXStartCoord, yPoint[i], paint);
				break;
			case 5:
				paint.setColor(0xFF781631);
				canvas.drawLine(yLineXStartCoord, yPoint[i - 1],
						yLineXStartCoord, yPoint[i], paint);
				break;
			default:
				break;
			}
			paint.setColor(Color.WHITE);
			paint.setTextSize(14);
			paint.setTypeface(font);
			paint.setTextAlign(Align.RIGHT);
			canvas.drawText(yScaleLeftLabel[i], yLineXStartCoord - 6,
					yPoint[i], paint);
			paint.setTextAlign(Align.LEFT);
			if (i == 0) {
				canvas.drawText(yScaleRightLabel[i], yLineXStartCoord + 6,
						(xLineYStartCoord + yPoint[i]) / 2, paint);
			} else {
				canvas.drawText(yScaleRightLabel[i], yLineXStartCoord + 6,
						(yPoint[i - 1] + yPoint[i]) / 2, paint);
			}
		}

		// 绘制折现
		float stepX = (float) xLineLength / 25.0f;
		float lowStepY = (float) (yLineLength - (yStep * 2)) / 200.0f;
		float middleStepY = (float) yStep / 100.0f;
		float highStepY = (float) yStep / 200.0f;
		for (int z = 0; z < lineInfos.size(); z++) {
			LineInfo lineInfo = lineInfos.get(z);

			int lastStepX = -1;
			int lastStepY = -1;
			for (int j = 0; j < lineInfo.getPoints().length; j++) {
				// 确定点的位置
				int pointX = xLineXStartCoord + (int) (j * stepX);
				int pointY = 0;
				if (lineInfo.getPoints()[j] >= 500) {
					pointY = yLineYEndCoord;
				} else if (lineInfo.getPoints()[j] >= 200) {
					if (lineInfo.getPoints()[j] > 300) {
						int high = lineInfo.getPoints()[j] - 300;
						pointY += (high * highStepY);
						pointY += (100 * middleStepY);
					} else {
						int middle = lineInfo.getPoints()[j] - 200;
						pointY += (middle * middleStepY);
					}
					pointY += (200 * lowStepY);
					pointY = yLineYStartCoord - pointY;
				} else {
					pointY = yLineYStartCoord
							- (int) (lowStepY * lineInfo.getPoints()[j]);
				}

				// 画点
				paint.setColor(lineInfo.getPointColor());
				canvas.drawCircle(pointX, pointY, 3, paint);

				// 连线
				if (lastStepX != -1 && lastStepY != -1) {
					paint.setColor(lineInfo.getLineColor());
					paint.setStrokeWidth(1.5f);
					canvas.drawLine(lastStepX, lastStepY, pointX, pointY, paint);
				}

				// 记录
				lastStepX = pointX;
				lastStepY = pointY;
			}

			// 在图表画折现标识
			int markY = this.getBottom() - 40;
			int markX = xLineXStartCoord
					+ (xLineLength / (lineInfos.size() + 1)) * (z + 1) - 30;

			paint.setColor(lineInfo.getPointColor());
			canvas.drawCircle(markX, markY, 3, paint);
			paint.setColor(lineInfo.getLineColor());
			paint.setStrokeWidth(1.5f);
			canvas.drawLine(markX - 10, markY, markX + 10, markY, paint);
			paint.setColor(Color.WHITE);
			paint.setTextAlign(Align.LEFT);
			canvas.drawText(lineInfo.getName(), markX + 10, markY + 5, paint);
		}

	}

	public CharInfo getCharInfo() {
		return charInfo;
	}

	public void setCharInfo(CharInfo charInfo) {
		this.charInfo = charInfo;
	}

	public List<LineInfo> getLineInfos() {
		return lineInfos;
	}

	public void setLineInfos(List<LineInfo> lineInfos) {
		this.lineInfos = lineInfos;
	}

}

 控件调用:

package com.example.customwidget;

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

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		LineChart lineChart = (LineChart) findViewById(R.id.lineChart);
		
		CharInfo charInfo = new CharInfo();
		charInfo.setTitle("最近24小时空气质量指数");
		charInfo.setxScaleNum(6);
		charInfo.setyScaleNum(6);
		String[] yScaleLeftLable = new String[6];
		yScaleLeftLable[0] = "50";
		yScaleLeftLable[1] = "100";
		yScaleLeftLable[2] = "150";
		yScaleLeftLable[3] = "200";
		yScaleLeftLable[4] = "300";
		yScaleLeftLable[5] = "500";
		charInfo.setyScaleLeftLable(yScaleLeftLable);
		String[] yScaleRightLable = new String[6];
		yScaleRightLable[0] = "优";
		yScaleRightLable[1] = "良";
		yScaleRightLable[2] = "轻度污染";
		yScaleRightLable[3] = "中度污染";
		yScaleRightLable[4] = "重度污染";
		yScaleRightLable[5] = "严重污染";
		charInfo.setyScaleRightLable(yScaleRightLable);
		String[] xScaleDownLable = new String[7];
		xScaleDownLable[0] = "21:00";
		xScaleDownLable[1] = "01:00";
		xScaleDownLable[2] = "05:00";
		xScaleDownLable[3] = "09:00";
		xScaleDownLable[4] = "13:00";
		xScaleDownLable[5] = "17:00";
		xScaleDownLable[6] = "21:00";
		charInfo.setxScaleDownLable(xScaleDownLable);
		
		lineChart.setCharInfo(charInfo);
		
		List<LineInfo> lineInfos = new ArrayList<LineInfo>();
		
		LineInfo lineInfo1 = new LineInfo();
		lineInfo1.setPointColor(0xFFE5B814);
		lineInfo1.setLineColor(0xFFC8A724);
		lineInfo1.setName("美国领事馆");
		lineInfo1.setPoints(new int[]{570,450,350,250,130,
				170,190,185,177,165,155,150,168,170,190,
				200,210,205,230,220,210,190,180,190,170,
				180});
		lineInfos.add(lineInfo1);
		
		LineInfo lineInfo2 = new LineInfo();
		lineInfo2.setPointColor(0xFF06D606);
		lineInfo2.setLineColor(0xFF99CC00);
		lineInfo2.setName("静安监测站");
		lineInfo2.setPoints(new int[]{170,150,250,300,170,
				120,130,165,147,265,255,170,268,180,160,
				240,220,215,200,210,240,180,190,200,270,
				190});
		lineInfos.add(lineInfo2);
		
		lineChart.setLineInfos(lineInfos);
		
		
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

 

 附:两个Bean

package com.example.customwidget;

import java.util.List;

public class CharInfo {
	private String title;
	private int yScaleNum;
	private String[] yScaleLeftLable;
	private String[] yScaleRightLable;
	private int xScaleNum;
	private String[] xScaleUpLable;
	private String[] xScaleDownLable;
	private List<LineInfo> lineInfos;

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public int getyScaleNum() {
		return yScaleNum;
	}

	public void setyScaleNum(int yScaleNum) {
		this.yScaleNum = yScaleNum;
	}

	public String[] getyScaleLeftLable() {
		return yScaleLeftLable;
	}

	public void setyScaleLeftLable(String[] yScaleLeftLable) {
		this.yScaleLeftLable = yScaleLeftLable;
	}

	public String[] getyScaleRightLable() {
		return yScaleRightLable;
	}

	public void setyScaleRightLable(String[] yScaleRightLable) {
		this.yScaleRightLable = yScaleRightLable;
	}

	public int getxScaleNum() {
		return xScaleNum;
	}

	public void setxScaleNum(int xScaleNum) {
		this.xScaleNum = xScaleNum;
	}

	public String[] getxScaleUpLable() {
		return xScaleUpLable;
	}

	public void setxScaleUpLable(String[] xScaleUpLable) {
		this.xScaleUpLable = xScaleUpLable;
	}

	public String[] getxScaleDownLable() {
		return xScaleDownLable;
	}

	public void setxScaleDownLable(String[] xScaleDownLable) {
		this.xScaleDownLable = xScaleDownLable;
	}

	public List<LineInfo> getLineInfos() {
		return lineInfos;
	}

	public void setLineInfos(List<LineInfo> lineInfos) {
		this.lineInfos = lineInfos;
	}

}

 

package com.example.customwidget;

public class LineInfo {
	private String name;
	private int pointColor;
	private int lineColor;
	private int[] points;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPointColor() {
		return pointColor;
	}

	public void setPointColor(int pointColor) {
		this.pointColor = pointColor;
	}

	public int getLineColor() {
		return lineColor;
	}

	public void setLineColor(int lineColor) {
		this.lineColor = lineColor;
	}

	public int[] getPoints() {
		return points;
	}

	public void setPoints(int[] points) {
		this.points = points;
	}

}

 

OK,That's all!

分享到:
评论
1 楼 zenmshuo 2016-09-19  
很不错,之前都是用Spread Studio实现的折线图

相关推荐

    android自定义折线图表格控件

    本主题聚焦于“android自定义折线图表格控件”,这是一个通过在Canvas上直接绘制来实现的自定义控件,它允许开发者展示多条线的数据,并提供了丰富的自定义选项。 首先,我们要理解Android中的自定义控件是如何工作...

    android自定义的折线图控件

    "android自定义的折线图控件"就是这样一个实例,它允许开发者根据需求绘制出折线图,并且支持设置折点的点击事件,从而为用户提供交互性的图表展示。下面将详细讲解这个控件的相关知识点。 首先,我们要理解折线图...

    Android自定义控件实现折线图

    Android自定义控件实现折线图 Android平台提供了多种方式来实现折线图,但是使用自定义控件来实现折线图可以提供更多的灵活性和自定义性。下面将详细介绍如何使用Android自定义控件实现折线图。 首先,需要在布局...

    Android开发自定义控件之折线图实现方法详解

    总结起来,Android自定义控件实现折线图的关键步骤包括: 1. 继承自View并重写`onDraw()`和`onMeasure()`方法。 2. 初始化和配置画笔,设置颜色、样式等。 3. 解析数据源并计算各数据点的坐标。 4. 在`onDraw()`中...

    Android之自定义控件实现天气温度折线图和饼状图

    本文将深入探讨如何利用Android SDK来实现自定义控件,具体是创建一个能够显示天气温度的折线图以及饼状图。首先,我们需要理解Android绘图的基础知识。 Android提供了多种绘图API,如Canvas、Paint、Path等,它们...

    Android自定义控件

    本压缩包文件"Android自定义控件"提供了一系列的手工绘制的视图组件,涵盖了饼状图、雷达图、阴阳鱼、不规则按钮、贝塞尔曲线、圆形进度条、弧形进度条、折线图、涂鸦和波浪等丰富的自定义视图。这些控件不仅展示出...

    Android自定义饼状图、柱状图、双折线图

    一开始是使用第三方的绘图框架Achartengine来绘制,能实现一大部分的图形。...为此小编我只能尝试着自己自定义一些图表类的控件。这里给大家带来可点击的饼状图、可点击以及可滑动的柱状图、双折线图

    自定义控件仿天气折线图的绘制,有天气图片 温度显示等

    本文将深入探讨如何根据提供的标题和描述,创建一个自定义控件来模仿天气的折线图,其中包括天气图片和温度显示功能。我们将从以下几个方面进行讨论: 1. **自定义View的基本结构** 自定义控件通常继承自`View`或`...

    自定义折线图Demo

    通过学习和实践"自定义折线图Demo",开发者不仅能掌握自定义控件的基本原理,还能深入了解Android图形绘制机制,提升在复杂UI设计上的能力。这个Demo的应用场景广泛,可应用于数据分析、股票图表、健康监测等多种...

    自定义控件如圆环比例图、折线图、ViewPager指示器、自定义简易表盘

    本文将深入探讨如何创建和使用标题中提到的几种自定义控件:圆环比例图、折线图、ViewPager指示器以及自定义简易表盘。我们将涵盖每个控件的基本原理、实现方法以及在实际项目中的应用。 首先,我们来看圆环比例图...

    自定义控件---实现天气折线图效果

    综上所述,实现自定义天气折线图控件需要掌握Android自定义View的原理,包括绘图API的使用、资源管理、事件处理等。通过这个过程,开发者不仅可以提升自身技能,还能为用户带来更具个性化的交互体验。在实际开发中,...

    Android自定义View简易折线图控件(二)

    本教程主要讲解如何创建一个自定义的简易折线图控件。这个控件支持坐标点的点击监听,适用于简单的数据可视化场景。 首先,我们需要定义自定义View的属性。在`res/values/attrs.xml`文件中,我们创建了一个名为`...

    Android自定义View实现折线图效果

    本示例介绍如何自定义一个折线图控件,适用于展示一系列状态,并支持用户滑动查看。以下是实现这一功能的关键步骤和知识点: 1. **自定义View的基本结构**: 首先,你需要创建一个新的Java类,如`LineCharView`,...

    自定义类继承view实现自定义控件

    在Android开发中,自定义控件是提升应用特色和用户体验的重要手段。自定义类继承View是创建自定义控件的基本方法。在这个过程中,开发者需要理解View的生命周期、绘图机制以及事件处理等核心概念。接下来,我们将...

    几个自定义控件的源码

    通过学习和研究这些自定义控件的源码,开发者不仅可以了解各种Android自定义控件的实现原理,还能掌握如何优化性能、处理触摸事件、动画效果以及数据可视化等方面的知识。这些实践案例对于提升个人技能和项目开发...

    Android自定义可左右滑动和点击的折线图

    Android自定义可左右滑动和点击的折线图是一种非常实用的图表控件,能够满足各种项目的需求。通过自定义view,开发者可以自由地设置折线图的样式、颜色、文字大小等属性,实现了高度的自定义性。 首先,在自定义...

    hellocharts-line.rar_安卓折线图控件_折线图 eclipse

    本文将详细介绍一个基于Eclipse开发的安卓折线图控件——"hellocharts-line",以及如何在实际项目中使用和自定义这个控件。 "hellocharts-line.rar" 是一个压缩包文件,其中包含了一个用于在Android设备上显示折线...

    Android自定义控件实现饼状图

    Android 自定义控件实现饼状图 ...10. 自定义控件的应用:自定义控件可以应用于各种场景,例如饼状图、柱状图、折线图等。在本例中,自定义控件用来实现饼状图的绘制,提供了一种灵活的方式来实现图形的绘制。

Global site tag (gtag.js) - Google Analytics