最近项目里要做一个简单的曲线图来标识数据,开始以为很简单,android已经有那么多的开源图表库了,什么achartenginee,hellochart,mpandroidchart等等,下载Demo一找,都强大到有点不适合我这个小小的展示功能了,直是无语了。于是只能自已去画了,继承自View去重绘。
下面先看一下效果图:
思路:根据点的数量将Canvas等分,等分后先绘制图表的所有横轴和纵轴。再将数据转化为点坐标,绘制到屏幕上,最后将相邻两点连成线即可。
源码如下:
- import android.content.Context;
- import android.content.res.Resources;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.Paint.Style;
- import android.graphics.Path;
- import android.graphics.Point;
- import android.util.AttributeSet;
- import android.util.DisplayMetrics;
- import android.view.View;
- import android.view.WindowManager;
- /**********************************************************
- * @文件名称:LineGraphicView.java
- * @文件作者:rzq
- * @创建时间:2015年5月27日 下午3:05:19
- * @文件描述:自定义简单曲线图
- * @修改历史:2015年5月27日创建初始版本
- **********************************************************/
- class LineGraphicView extends View
- {
- /**
- * 公共部分
- */
- private static final int CIRCLE_SIZE = 10;
- private static enum Linestyle
- {
- Line, Curve
- }
- private Context mContext;
- private Paint mPaint;
- private Resources res;
- private DisplayMetrics dm;
- /**
- * data
- */
- private Linestyle mStyle = Linestyle.Curve;
- private int canvasHeight;
- private int canvasWidth;
- private int bheight = 0;
- private int blwidh;
- private boolean isMeasure = true;
- /**
- * Y轴最大值
- */
- private int maxValue;
- /**
- * Y轴间距值
- */
- private int averageValue;
- private int marginTop = 20;
- private int marginBottom = 40;
- /**
- * 曲线上总点数
- */
- private Point[] mPoints;
- /**
- * 纵坐标值
- */
- private ArrayList<Double> yRawData;
- /**
- * 横坐标值
- */
- private ArrayList<String> xRawDatas;
- private ArrayList<Integer> xList = new ArrayList<Integer>();// 记录每个x的值
- private int spacingHeight;
- public LineGraphicView(Context context)
- {
- this(context, null);
- }
- public LineGraphicView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- this.mContext = context;
- initView();
- }
- private void initView()
- {
- this.res = mContext.getResources();
- this.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- dm = new DisplayMetrics();
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getMetrics(dm);
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh)
- {
- if (isMeasure)
- {
- this.canvasHeight = getHeight();
- this.canvasWidth = getWidth();
- if (bheight == 0)
- bheight = (int) (canvasHeight - marginBottom);
- blwidh = dip2px(30);
- isMeasure = false;
- }
- }
- @Override
- protected void onDraw(Canvas canvas)
- {
- mPaint.setColor(res.getColor(R.color.color_f2f2f2));
- drawAllXLine(canvas);
- // 画直线(纵向)
- drawAllYLine(canvas);
- // 点的操作设置
- mPoints = getPoints();
- mPaint.setColor(res.getColor(R.color.color_ff4631));
- mPaint.setStrokeWidth(dip2px(2.5f));
- mPaint.setStyle(Style.STROKE);
- if (mStyle == Linestyle.Curve)
- {
- drawScrollLine(canvas);
- }
- else
- {
- drawLine(canvas);
- }
- mPaint.setStyle(Style.FILL);
- for (int i = 0; i < mPoints.length; i++)
- {
- canvas.drawCircle(mPoints[i].x, mPoints[i].y, CIRCLE_SIZE / 2, mPaint);
- }
- }
- /**
- * 画所有横向表格,包括X轴
- */
- private void drawAllXLine(Canvas canvas)
- {
- for (int i = 0; i < spacingHeight + 1; i++)
- {
- canvas.drawLine(blwidh, bheight - (bheight / spacingHeight) * i + marginTop, (canvasWidth - blwidh),
- bheight - (bheight / spacingHeight) * i + marginTop, mPaint);// Y坐标
- drawText(String.valueOf(averageValue * i), blwidh / 2, bheight - (bheight / spacingHeight) * i + marginTop,
- canvas);
- }
- }
- /**
- * 画所有纵向表格,包括Y轴
- */
- private void drawAllYLine(Canvas canvas)
- {
- for (int i = 0; i < yRawData.size(); i++)
- {
- xList.add(blwidh + (canvasWidth - blwidh) / yRawData.size() * i);
- canvas.drawLine(blwidh + (canvasWidth - blwidh) / yRawData.size() * i, marginTop, blwidh
- + (canvasWidth - blwidh) / yRawData.size() * i, bheight + marginTop, mPaint);
- drawText(xRawDatas.get(i), blwidh + (canvasWidth - blwidh) / yRawData.size() * i, bheight + dip2px(26),
- canvas);// X坐标
- }
- }
- private void drawScrollLine(Canvas canvas)
- {
- Point startp = new Point();
- Point endp = new Point();
- for (int i = 0; i < mPoints.length - 1; i++)
- {
- startp = mPoints[i];
- endp = mPoints[i + 1];
- int wt = (startp.x + endp.x) / 2;
- Point p3 = new Point();
- Point p4 = new Point();
- p3.y = startp.y;
- p3.x = wt;
- p4.y = endp.y;
- p4.x = wt;
- Path path = new Path();
- path.moveTo(startp.x, startp.y);
- path.cubicTo(p3.x, p3.y, p4.x, p4.y, endp.x, endp.y);
- canvas.drawPath(path, mPaint);
- }
- }
- private void drawLine(Canvas canvas)
- {
- Point startp = new Point();
- Point endp = new Point();
- for (int i = 0; i < mPoints.length - 1; i++)
- {
- startp = mPoints[i];
- endp = mPoints[i + 1];
- canvas.drawLine(startp.x, startp.y, endp.x, endp.y, mPaint);
- }
- }
- private void drawText(String text, int x, int y, Canvas canvas)
- {
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
- p.setTextSize(dip2px(12));
- p.setColor(res.getColor(R.color.color_999999));
- p.setTextAlign(Paint.Align.LEFT);
- canvas.drawText(text, x, y, p);
- }
- private Point[] getPoints()
- {
- Point[] points = new Point[yRawData.size()];
- for (int i = 0; i < yRawData.size(); i++)
- {
- int ph = bheight - (int) (bheight * (yRawData.get(i) / maxValue));
- points[i] = new Point(xList.get(i), ph + marginTop);
- }
- return points;
- }
- public void setData(ArrayList<Double> yRawData, ArrayList<String> xRawData, int maxValue, int averageValue)
- {
- this.maxValue = maxValue;
- this.averageValue = averageValue;
- this.mPoints = new Point[yRawData.size()];
- this.xRawDatas = xRawData;
- this.yRawData = yRawData;
- this.spacingHeight = maxValue / averageValue;
- }
- public void setTotalvalue(int maxValue)
- {
- this.maxValue = maxValue;
- }
- public void setPjvalue(int averageValue)
- {
- this.averageValue = averageValue;
- }
- public void setMargint(int marginTop)
- {
- this.marginTop = marginTop;
- }
- public void setMarginb(int marginBottom)
- {
- this.marginBottom = marginBottom;
- }
- public void setMstyle(Linestyle mStyle)
- {
- this.mStyle = mStyle;
- }
- public void setBheight(int bheight)
- {
- this.bheight = bheight;
- }
- /**
- * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
- */
- private int dip2px(float dpValue)
- {
- return (int) (dpValue * dm.density + 0.5f);
- }
- }
使用:
- package com.example;
- import java.util.ArrayList;
- import android.app.Activity;
- import android.os.Bundle;
- public class MainActivity extends Activity
- {
- LineGraphicView tu;
- ArrayList<Double> yList;
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- tu = (LineGraphicView) findViewById(R.id.line_graphic);
- yList = new ArrayList<Double>();
- yList.add((double) 2.103);
- yList.add(4.05);
- yList.add(6.60);
- yList.add(3.08);
- yList.add(4.32);
- yList.add(2.0);
- yList.add(5.0);
- ArrayList<String> xRawDatas = new ArrayList<String>();
- xRawDatas.add("05-19");
- xRawDatas.add("05-20");
- xRawDatas.add("05-21");
- xRawDatas.add("05-22");
- xRawDatas.add("05-23");
- xRawDatas.add("05-24");
- xRawDatas.add("05-25");
- xRawDatas.add("05-26");
- tu.setData(yList, xRawDatas, 8, 2);
- }