先看圖

BrokenLine.png
分析圖表
首先我們根據(jù)上圖我們可以看到如下幾個(gè)元素
- 邊框線
![5FXGL_@$E{Y)R{}L~1V$]7R.png](http://upload-images.jianshu.io/upload_images/6544862-a5cc5c5619226bea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 邊框線數(shù)據(jù)值

BrokenLineData.png
- 邊框線內(nèi)折線

Line.png
- 折線上的圓
如上分析,我們所需要繪制的就是邊框線,框線分段數(shù)據(jù)值,框內(nèi)折線,折線上的圓
在畫圖之前 我們首先得 準(zhǔn)備一些 必要參數(shù)
<code>
/**View寬度*/
private int mViewWidth;
/** View高度*/
private int mViewHeight;
/**邊框線畫筆*/
private Paint mBorderLinePaint;
/**文本畫筆*/
private Paint mTextPaint;
/**要繪制的折線線畫筆*/
private Paint mBrokenLinePaint;
/**圓畫筆*/
private Paint mCirclePaint;
/**圓的半徑*/
private float radius=5;
/**邊框的左邊距*/
private float mBrokenLineLeft=40;
/**邊框的上邊距*/
private float mBrokenLineTop=40;
/**邊框的下邊距*/
private float mBrokenLineBottom=40;
/**邊框的右邊距*/
private float mBrokenLinerRight=20;
/**需要繪制的寬度*/
private float mNeedDrawWidth;
/**需要繪制的高度*/
private float mNeedDrawHeight;
/**邊框文本*/
private int[] valueText =new int[]{40,30,20,10,0};
/**數(shù)據(jù)值*/
private int[] value=new int[]{11,10,15,12,34,12,22,23,33,13};
/**圖表的最大值*/
private int maxVlaue=40;
</code>
參數(shù)準(zhǔn)備好 首先 重寫onMeasure 初始化參數(shù)
<code>
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mViewHeight = getMeasuredHeight();
mViewWidth = getMeasuredWidth();
initNeedDrawWidthAndHeight();
initPaint();
}
/**初始化繪制折線圖的寬高*/
private void initNeedDrawWidthAndHeight(){
mNeedDrawWidth = mViewWidth-mBrokenLineLeft-mBrokenLinerRight;
mNeedDrawHeight = mViewHeight-mBrokenLineTop-mBrokenLineBottom;
}
/**初始化畫筆*/
private void initPaint() {
/**初始化文本畫筆*/
if(mTextPaint==null){
mTextPaint=new Paint();
}
initPaint(mTextPaint);
/**初始化邊框線畫筆*/
if(mBorderLinePaint==null){
mBorderLinePaint=new Paint();
mBorderLinePaint.setTextSize(20);
}
initPaint(mBorderLinePaint);
/**初始化折線畫筆*/
if(mBrokenLinePaint==null){
mBrokenLinePaint=new Paint();
}
initPaint(mBrokenLinePaint);
if(mCirclePaint==null){
mCirclePaint=new Paint();
}
initPaint(mCirclePaint);
}
/**初始化畫筆默認(rèn)屬性*/
private void initPaint(Paint paint){
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
}
</code>
這個(gè)時(shí)候我們的一切參數(shù) 都準(zhǔn)備好了 首先我們來(lái)完成邊線框的繪制
![5FXGL_@$E{Y)R{}L~1V$]7R.png](http://upload-images.jianshu.io/upload_images/6544862-a5cc5c5619226bea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<code>
/**繪制邊框豎線*/
canvas.drawLine(mBrokenLineLeft,mBrokenLineTop-10,mBrokenLineLeft,mViewHeight-mBrokenLineBottom,mBorderLinePaint);
/**繪制邊框橫線*/
canvas.drawLine(mBrokenLineLeft,mViewHeight-mBrokenLineBottom,mViewWidth,mViewHeight-mBrokenLineBottom,mBorderLinePaint);
</code>
邊線框值的繪制

BrokenLineData.png
<code>
/**繪制邊線框的值*/
float averageHeight=mNeedDrawHeight/(valueText.length-1);
mBorderLinePaint.setTextAlign(Paint.Align.RIGHT);
mBorderLinePaint.setColor(Color.GRAY);
for (int i = 0; i < valueText.length; i++) {
float nowadayHeight= averageHeight*i;
canvas.drawLine(mBrokenLineLeft,nowadayHeight+mBrokenLineTop,mViewWidth-mBrokenLinerRight,nowadayHeight+mBrokenLineTop,mBorderLinePaint);
canvas.drawText(valueText[i]+"",mBrokenLineLeft-5,nowadayHeight+mBrokenLineTop,mBorderLinePaint);
}
</code>
繪制框內(nèi)的線

Line.png
<code>
/**根據(jù)值繪制折線*/
private void DrawBrokenLine(Canvas canvas) {
Path mPath=new Path();
mBrokenLinePaint.setColor(Color.BLUE);
mBrokenLinePaint.setStrokeWidth(2);
Point[] points= getPoints(value,mNeedDrawHeight,mNeedDrawWidth,maxVlaue,mBrokenLineLeft,mBrokenLineTop);
for (int i = 0; i < points.length; i++) {
Point point=points[i];
if(i==0){
mPath.moveTo(point.x,point.y);
}else {
mPath.lineTo(point.x,point.y);
}
}
canvas.drawPath(mPath,mBrokenLinePaint);
}
/**根據(jù)值計(jì)算在該值的 x,y坐標(biāo)*/
public Point[] getPoints(int[] values, float height, float width, int max , float left,float top) {
float leftPading = width / (values.length-1);//繪制邊距
Point[] points = new Point[values.length];
for (int i = 0; i < values.length; i++) {
float value = values[i];
//計(jì)算每點(diǎn)高度所以對(duì)應(yīng)的值
double mean = (double) max/height;
//獲取要繪制的高度
float drawHeight = (float) (value / mean);
int pointY = (int) (height+top - drawHeight);
int pointX = (int) (leftPading * i + left);
Point point = new Point(pointX, pointY);
points[i] = point;
}
return points;
}
</code>
繪制線上的圓
<code>
/**繪制線上的圓*/
private void DrawLineCircle(Canvas canvas) {
Point[] points= getPoints(value,mNeedDrawHeight,mNeedDrawWidth,maxVlaue,mBrokenLineLeft,mBrokenLineTop);
for (int i = 0; i <points.length ; i++) {
Point point=points[i];
mCirclePaint.setColor(Color.WHITE);
mCirclePaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(point.x,point.y,radius,mCirclePaint);
mCirclePaint.setColor(Color.BLUE);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeWidth(3);
/**
* drawCircle(float cx, float cy, float radius, Paint paint)
* cx 中間x坐標(biāo)
* xy 中間y坐標(biāo)
* radius 圓的半徑
* paint 繪制圓的畫筆
* */
canvas.drawCircle(point.x,point.y,radius,mCirclePaint);
}
}
</code>
那么完整的代碼如下
<code>
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
public class BrokenLineChart extends View {
private static final String TAG = "BrokenLineChart";
/**View寬度*/
private int mViewWidth;
/** View高度*/
private int mViewHeight;
/**邊框線畫筆*/
private Paint mBorderLinePaint;
/**文本畫筆*/
private Paint mTextPaint;
/**要繪制的折線線畫筆*/
private Paint mBrokenLinePaint;
/**圓畫筆*/
private Paint mCirclePaint;
/**圓的半徑*/
private float radius=5;
/**邊框的左邊距*/
private float mBrokenLineLeft=40;
/**邊框的上邊距*/
private float mBrokenLineTop=40;
/**邊框的下邊距*/
private float mBrokenLineBottom=40;
/**邊框的右邊距*/
private float mBrokenLinerRight=20;
/**需要繪制的寬度*/
private float mNeedDrawWidth;
/**需要繪制的高度*/
private float mNeedDrawHeight;
/**邊框文本*/
private int[] valueText =new int[]{40,30,20,10,0};
/**數(shù)據(jù)值*/
private int[] value=new int[]{11,10,15,12,34,12,22,23,33,13};
/**圖表的最大值*/
private int maxVlaue=40;
public BrokenLineChart(Context context) {
super(context);
}
public BrokenLineChart(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mViewHeight = getMeasuredHeight();
mViewWidth = getMeasuredWidth();
initNeedDrawWidthAndHeight();
initPaint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**繪制邊框線和邊框文本*/
DrawBorderLineAndText(canvas);
/**根據(jù)數(shù)據(jù)繪制線*/
DrawBrokenLine(canvas);
DrawLineCircle(canvas);
}
/**繪制線上的圓*/
private void DrawLineCircle(Canvas canvas) {
Point[] points= getPoints(value,mNeedDrawHeight,mNeedDrawWidth,maxVlaue,mBrokenLineLeft,mBrokenLineTop);
for (int i = 0; i <points.length ; i++) {
Point point=points[i];
mCirclePaint.setColor(Color.WHITE);
mCirclePaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(point.x,point.y,radius,mCirclePaint);
mCirclePaint.setColor(Color.BLUE);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeWidth(3);
/**
* drawCircle(float cx, float cy, float radius, Paint paint)
* cx 中間x坐標(biāo)
* xy 中間y坐標(biāo)
* radius 圓的半徑
* paint 繪制圓的畫筆
* */
canvas.drawCircle(point.x,point.y,radius,mCirclePaint);
}
}
/**根據(jù)值繪制折線*/
private void DrawBrokenLine(Canvas canvas) {
Path mPath=new Path();
mBrokenLinePaint.setColor(Color.BLUE);
mBrokenLinePaint.setStrokeWidth(2);
Point[] points= getPoints(value,mNeedDrawHeight,mNeedDrawWidth,maxVlaue,mBrokenLineLeft,mBrokenLineTop);
for (int i = 0; i < points.length; i++) {
Point point=points[i];
if(i==0){
mPath.moveTo(point.x,point.y);
}else {
mPath.lineTo(point.x,point.y);
}
}
canvas.drawPath(mPath,mBrokenLinePaint);
}
/**繪制邊框線和邊框文本*/
private void DrawBorderLineAndText(Canvas canvas) {
/**對(duì)應(yīng)的屬性
* drawLine(float startX, float startY, float stopX, float stopY, Paint paint);
* startX 開始的x坐標(biāo)
* startY 開始的y坐標(biāo)
* stopX 結(jié)束的x坐標(biāo)
* stopY 結(jié)束的y坐標(biāo)
* paint 繪制該線的畫筆
* */
mBorderLinePaint.setColor(Color.BLACK);
/**繪制邊框豎線*/
canvas.drawLine(mBrokenLineLeft,mBrokenLineTop-10,mBrokenLineLeft,mViewHeight-mBrokenLineBottom,mBorderLinePaint);
/**繪制邊框橫線*/
canvas.drawLine(mBrokenLineLeft,mViewHeight-mBrokenLineBottom,mViewWidth,mViewHeight-mBrokenLineBottom,mBorderLinePaint);
/**繪制邊框分段橫線與分段文本*/
float averageHeight=mNeedDrawHeight/(valueText.length-1);
mBorderLinePaint.setTextAlign(Paint.Align.RIGHT);
mBorderLinePaint.setColor(Color.GRAY);
for (int i = 0; i < valueText.length; i++) {
float nowadayHeight= averageHeight*i;
canvas.drawLine(mBrokenLineLeft,nowadayHeight+mBrokenLineTop,mViewWidth-mBrokenLinerRight,nowadayHeight+mBrokenLineTop,mBorderLinePaint);
canvas.drawText(valueText[i]+"",mBrokenLineLeft-5,nowadayHeight+mBrokenLineTop,mBorderLinePaint);
}
}
/**初始化畫筆*/
private void initPaint() {
/**初始化文本畫筆*/
if(mTextPaint==null){
mTextPaint=new Paint();
}
initPaint(mTextPaint);
/**初始化邊框線畫筆*/
if(mBorderLinePaint==null){
mBorderLinePaint=new Paint();
mBorderLinePaint.setTextSize(20);
}
initPaint(mBorderLinePaint);
/**初始化折線畫筆*/
if(mBrokenLinePaint==null){
mBrokenLinePaint=new Paint();
}
initPaint(mBrokenLinePaint);
if(mCirclePaint==null){
mCirclePaint=new Paint();
}
initPaint(mCirclePaint);
}
/**初始化畫筆默認(rèn)屬性*/
private void initPaint(Paint paint){
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
}
/**初始化繪制折線圖的寬高*/
private void initNeedDrawWidthAndHeight(){
mNeedDrawWidth = mViewWidth-mBrokenLineLeft-mBrokenLinerRight;
mNeedDrawHeight = mViewHeight-mBrokenLineTop-mBrokenLineBottom;
}
/**根據(jù)值計(jì)算在該值的 x,y坐標(biāo)*/
public Point[] getPoints(int[] values, float height, float width, int max , float left,float top) {
float leftPading = width / (values.length-1);//繪制邊距
Point[] points = new Point[values.length];
for (int i = 0; i < values.length; i++) {
float value = values[i];
//計(jì)算每點(diǎn)高度所以對(duì)應(yīng)的值
double mean = (double) max/height;
//獲取要繪制的高度
float drawHeight = (float) (value / mean);
int pointY = (int) (height+top - drawHeight);
int pointX = (int) (leftPading * i + left);
Point point = new Point(pointX, pointY);
points[i] = point;
}
return points;
}
}
</code>