# 用自定义View绘制带刻度尺的正方体

#### 下面就直接进入主题：

1.绘制的逻辑：

2.代码详解：

2.1.绘制X、Y轴

public void drawExample(Canvas canvas, Rect rect) {

/** 绘制背景 */

canvas.drawRect(rect, paintBack);

// 需要根据矩形绘制出两条线 (即所谓的X、Y轴线)

int sx = rect.left, sy = rect.top, ex = rect.left, ey = rect.bottom;

canvas.drawLine(sx, sy, ex, ey, linePaint);// Y纵向的线段 左

/** sx2为表格起始点 */

int sx2 = rect.left, sy2 = rect.bottom, ex2 = rect.right, ey2 = rect.bottom;

canvas.drawLine(sx2, sy2, ex2, ey2, linePaint);// 横向的线段 下

int sx3 = rect.left, sy3 = rect.top, ex3 = rect.right, ey3 = rect.top;

canvas.drawLine(sx3, sy3, ex3, ey3, linePaint);// 上

int sx4 = rect.right, sy4 = rect.top, ex4 = rect.right, ey4 = rect.bottom;

canvas.drawLine(sx4, sy4, ex4, ey4, linePaint);// 右

/** X轴刻度间距 */

float spaceX = (rect.right - rect.left) / xNum;

for (int i = 0; i <= xNum; i++) {// 12是X轴共12个空隙

canvas.drawLine(rect.left + spaceX * i, rect.bottom, rect.left

+ spaceX * i, rect.bottom - 8, linePaint);// 刻度

canvas.drawText(xArr[i], rect.left + spaceX * i - 8,

rect.bottom + 25, paintDegree);// 文字

}

/** Y轴刻度间距 */

float spaceY = (rect.bottom - rect.top) / yNum;

for (int i = 0; i <= yNum; i++) {// 8是Y轴共8个空隙

canvas.drawLine(rect.left, rect.top + spaceY * i, rect.left + 8,

rect.top + spaceY * i, linePaint);// 刻度

canvas.drawText(yArr[i], rect.left - 35, rect.bottom - spaceY * i

+ 8, paintDegree);// 文字

}

/** 每点值的距离 */

xPxSpace = (rect.right - rect.left) / (xEnd - xStart);

/** 每点值的距离 */

yPxSpace = (rect.bottom - rect.top) / (yEnd - yStart);

if (isShowGraticule) {// 是否需要显示标线

// 50 zuo===555 you===355xia===20 shang

// 下面的值 (60、80、90、100 90、120、140、160 是标线值)

canvas.drawLine(rect.left, rect.bottom - (yMarkingOne - yStart)

* yPxSpace, rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom - (yMarkingOne - yStart) * yPxSpace, linePaint);// 3

canvas.drawLine(rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom, rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom - (yMarkingOne - yStart) * yPxSpace, linePaint);// 4

canvas.drawLine(rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom - (yMarkingOne - yStart) * yPxSpace,

rect.right, rect.top, linePaint);// 11

canvas.drawLine(rect.left, rect.bottom - (yMarkingOne - yStart)

* yPxSpace,

(rect.right - (xMarkingOne - xStart) * xPxSpace), rect.top,

linePaint);// 9

canvas.drawLine(rect.left, rect.bottom,

(rect.right - (xMarkingOne - xStart) * xPxSpace),

(yMarkingOne - yStart) * yPxSpace, linePaint);// 10

canvas.drawLine(rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom, (rect.right), (yMarkingOne - yStart)

* yPxSpace, linePaint);// 12

canvas.drawLine((rect.right - (xMarkingOne - xStart) * xPxSpace),

(yMarkingOne - yStart) * yPxSpace, (rect.right),

(yMarkingOne - yStart) * yPxSpace, linePaint);// 5

canvas.drawLine((rect.right - (xMarkingOne - xStart) * xPxSpace),

(yMarkingOne - yStart) * yPxSpace,

(rect.right - (xMarkingOne - xStart) * xPxSpace), rect.top,

linePaint);// 6

}

}

2.2.获得一个字符串的高度

public static int getStringHeight(Paint paint, String str) {

int height = 0;

Rect rect = new Rect();

paint.getTextBounds(str, 0, str.length(), rect);// 用一个矩形去"套"字符串,获得能完全套住字符串的最小矩形

height = rect.height();// 字符串的高度

return height;

}

2.3.绘制带刻度尺的正方全部代码及效果图

package com.example.scatter;

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.graphics.Rect;

import android.util.AttributeSet;

import android.view.View;

public class CustomScatterView extends View {

/** 数据接收数组 -- X轴上值 */

private int[] xData /*

* =

* {75,135,85,94,105,111,122,128,126,135,137,124,88,135

* ,148,154,172}

*/;

/** 数据接收数组 -- Y轴上值 */

private int[] yData /*

* =

* {35,45,85,64,75,81,92,88,86,85,87,84,88,75,88,94,102}

*/;

/** 绘制背景底色Paint */

private Paint paintBack;

/** 绘制刻度Paint(边沿的刻度值) */

private Paint paintDegree, paintX, paintY, paintZ;

/** 绘制线Paint(所谓的X、Y轴线) */

private Paint linePaint;

private Paint redlinePaint;

private Paint greedlinePaint;

/** 绘制虚线Paint(即介于XY中间的线条) */

private Paint dottedPaint;

/** 绘制圆点Paint */

private Paint circlePaint;

/** 承载分析图的矩形背景--矩形背景大小 */

private Rect rectBack;

/** X轴显示值 */

private String[] xArr /*

* =

* {"60","70","80","90","100","110","120","130","140","150"

* ,"160","170","180"}

*/;

/** Y轴显示值 */

private String[] yArr /* = {"30","40","50","60","70","80","90","100","110"} */;

/** X轴刻度数值间空隙数 默认12 */

private float xNum = 12;

/** Y轴刻度数值间空隙数 默认8 */

private float yNum = 8;

/** X轴的起始值 默认60 */

private float xStart = 60;

/** X轴的结束值 默认180 */

private float xEnd = 180;

/** Y轴的起始值 默认30 */

private float yStart = 30;

/** Y轴的结束值 默认110 */

private float yEnd = 110;

/** X轴值点之间的物理间距 */

private float xSpace;

/** Y轴值点之间的物理间距 */

private float ySpace;

/** X轴值点之间的像素间距 */

private float xPxSpace;

/** Y轴值点之间的像素间距 */

private float yPxSpace;

/** 是否需要显示标线 */

private boolean isShowGraticule = false;

/** 是否需要显示标线 */

public void setShowGraticule(boolean isShowGraticule) {

this.isShowGraticule = isShowGraticule;

}

// 下面的值 (60、80、90、100 90、120、140、160 是标线值)

/** X轴的第一个标线值 */

private int xMarkingOne = 100;

/** Y轴的第一个标线值 */

private int yMarkingOne = 100;

/**

* 设置X、Y轴上的标线值点 (下面的值 均 大于0 且不等于0 否则为默认值)

*

* @param xMarkingOne

*            默认为90

* @param xMarkingTwo

*            默认为120

* @param xMarkingThree

*            默认为140

* @param xMarkingFour

*            默认为160

* @param yMarkingOne

*            默认为60

* @param yMarkingTwo

*            默认为80

* @param yMarkingThree

*            默认为90

* @param yMarkingFour

*            默认为100

*/

public void setMarkingVlaue(int xMarkingOne, int xMarkingTwo,

int xMarkingThree, int xMarkingFour, int yMarkingOne,

int yMarkingTwo, int yMarkingThree, int yMarkingFour) {

if (xMarkingOne > 0)

this.xMarkingOne = xMarkingOne;

if (yMarkingOne > 0)

this.yMarkingOne = yMarkingOne;

}

/***

* 设置画图需要的值 (下面的值 均 大于0 且不等于0 否则为默认值)

*

* @param xNum

*            X轴需要显示多少(数据点值-1)(即数据点值的间隔空隙) 默认为12

* @param yNum

*            Y轴需要显示多少(数据点值-1)(即数据点值的间隔空隙) 默认为8

* @param xStart

*            X轴开始值 默认为 60

* @param xEnd

*            X轴结束值 默认为 180

* @param yStart

*            Y轴开始值 默认为 30

* @param yEnd

*            Y轴结束值 默认为 110

*/

public void setValue(float xNum, float yNum, float xStart, float xEnd,

float yStart, float yEnd) {

if (xNum != 0.0 && xNum > 0)

this.xNum = xNum;

if (yNum != 0.0 && yNum > 0)

this.yNum = yNum;

if (xStart <= xEnd && xStart >= 0) {

this.xStart = xStart;

this.xEnd = xEnd;

}

if (yStart <= yEnd && yStart >= 0) {

this.yStart = yStart;

this.yEnd = yEnd;

}

}

/**

* 给图形设置值

*

* @param xData

*            X轴需要显示的值

* @param yData

*            Y轴需要显示的值

*/

public void setVlaueData(int[] xData, int[] yData) {

this.xData = xData;

this.yData = yData;

invalidate();

}

public CustomScatterView(Context context) {

super(context, null, 0);

}

public CustomScatterView(Context context, AttributeSet attrs) {

super(context, attrs, 0);

}

public CustomScatterView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

/** 初始化信息 */

private void init() {

// 初始化默认值

paintBack = new Paint();// 画笔

paintBack.setColor(getResources().getColor(R.color.bar_view_bg));// 默认颜色

paintBack.setStyle(Paint.Style.FILL);// 填充色

redlinePaint = new Paint();

redlinePaint.setColor(Color.RED);

redlinePaint.setStrokeWidth(2);

redlinePaint.setStyle(Paint.Style.STROKE);

redlinePaint.setAntiAlias(true);

PathEffect effect = new DashPathEffect(new float[] { 1, 2, 4, 8 }, 1);

redlinePaint.setPathEffect(effect);

greedlinePaint = new Paint();

greedlinePaint.setColor(Color.GREEN);

greedlinePaint.setStrokeWidth(2);

greedlinePaint.setStrokeCap(Paint.Cap.ROUND);

greedlinePaint.setAntiAlias(true);

// 绘制刻度

paintDegree = new Paint();

paintDegree.setColor(Color.BLACK);

paintDegree.setTextSize(18);

paintDegree.setAntiAlias(true);// 锯齿不显示

paintX = new Paint();

paintX.setColor(Color.BLACK);

paintX.setTextSize(18);

paintX.setAntiAlias(true);// 锯齿不显示

paintY = new Paint();

paintY.setColor(Color.BLUE);

paintY.setTextSize(18);

paintY.setAntiAlias(true);// 锯齿不显示

paintZ = new Paint();

paintZ.setColor(Color.BLACK);

paintZ.setTextSize(18);

paintZ.setAntiAlias(true);// 锯齿不显示

// 绘制线

linePaint = new Paint();//

linePaint.setColor(Color.BLACK);

/** 设置线的宽度 **/

linePaint.setStrokeWidth(2);

/** 设置画笔变为圆滑状 **/

linePaint.setStrokeCap(Paint.Cap.ROUND);

linePaint.setAntiAlias(true);// 锯齿不显示

/** 绘制虚线 */

dottedPaint = new Paint();

dottedPaint.setAntiAlias(true);

dottedPaint.setStyle(Paint.Style.STROKE);

dottedPaint.setColor(Color.GRAY);

PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);

dottedPaint.setPathEffect(effects);

// 绘制比例小矩形

circlePaint = new Paint();

circlePaint.setColor(Color.RED);// 默认颜色

circlePaint.setStyle(Paint.Style.FILL);// 填充色

circlePaint.setAntiAlias(true);// 锯齿不显示

xSpace = (xEnd - xStart) / xNum;

ySpace = (yEnd - yStart) / yNum;

xArr = new String[(int) (xNum + 1)];

yArr = new String[(int) (yNum + 1)];

for (int i = 0; i <= xNum; i++) {

xArr[i] = (int) (xStart + xSpace * i) + "";

}

for (int i = 0; i <= yNum; i++) {

yArr[i] = (int) (yStart + ySpace * i) + "";

}

rectBack = new Rect(50, 20, getWidth() - 45, getHeight() - 45);// 默认矩形大小位置

}

@Override

protected void onLayout(boolean changed, int left, int top, int right,

int bottom) {

super.onLayout(changed, left, top, right, bottom);

init();

}

@Override

protected void onDraw(Canvas canvas) {

try {

super.onDraw(canvas);

// 设置画布背景颜色

canvas.drawColor(Color.WHITE);

drawExample(canvas, rectBack);

// drawCircle(canvas,rectBack,xData,yData);

drawLine3(canvas, rectBack, x, y, z);

} catch (Exception e) {

e.printStackTrace();

}

}

private float x, y, z;

public void setVlaueData(float x, float y, float z) {

this.x = x;

this.y = y;

this.z = z;

invalidate();

}

private static float xishu = (float) (30 / 45.0);// sina

private static float xishu1 = (float) (38 / 45.0);// cosa

/**

* 画3根线

*

* @param yData

* @param xData

*/

private void drawLine3(Canvas canvas, Rect rect, float x, float y, float z) {

// 绘制3根线

// float x0 = (float) (x + z * Math.cos(45*Math.PI/180));

// float y0 = (float) (y + z * Math.sin(45*Math.PI/180));

//

// float x1 = (float) (0 + z * Math.cos(45*Math.PI/180));

// float y1 = (float) (0 + z * Math.sin(45*Math.PI/180));

//

// float x2 = (float) (0 + 0 * Math.cos(45*Math.PI/180));

// float y2 = (float) (y + 0 * Math.sin(45*Math.PI/180));

//

// float x3 = (float) (x + 0 * Math.cos(45*Math.PI/180));

// float y3 = (float) (0 + 0 * Math.sin(45*Math.PI/180));

float x0 = (float) (x + z * xishu);

float y0 = (float) (y + z * xishu1);

float x1 = (float) (x + 0 * xishu);

float y1 = (float) (y + 0 * xishu1);

float x2 = (float) (0 + z * xishu);

float y2 = (float) (y + z * xishu1);

float x3 = (float) (x + z * xishu);

float y3 = (float) (0 + z * xishu1);

float x11 = (float) (x + 0 * xishu);

float y11 = (float) (0 + 0 * xishu1);

float x22 = (float) (0 + 0 * xishu);

float y22 = (float) (y + 0 * xishu1);

float x33 = (float) (0 + z * xishu);

float y33 = (float) (0 + z * xishu1);

// canvas.drawLine(rect.left + (x1-xStart)*xPxSpace, rect.bottom -

// (y1-yStart)*yPxSpace, rect.left + (x0-xStart)*xPxSpace, rect.bottom -

// (y0-yStart)*yPxSpace, redlinePaint);//x=0

// canvas.drawLine(rect.left + (x2-xStart)*xPxSpace, rect.bottom -

// (y2-yStart)*yPxSpace, rect.left + (x0-xStart)*xPxSpace, rect.bottom -

// (y0-yStart)*yPxSpace, redlinePaint);//y=0

// canvas.drawLine(rect.left + (x3-xStart)*xPxSpace, rect.bottom -

// (y3-yStart)*yPxSpace, rect.left + (x0-xStart)*xPxSpace, rect.bottom -

// (y0-yStart)*yPxSpace, redlinePaint);//z=0

DashPathEffect pathEffect = new DashPathEffect(new float[] { 3, 2 }, 0);

redlinePaint.setPathEffect(pathEffect);

Path path1 = new Path();

path1.moveTo(rect.left + (x1 - xStart) * xPxSpace, rect.bottom

- (y1 - yStart) * yPxSpace);

path1.lineTo(rect.left + (x0 - xStart) * xPxSpace, rect.bottom

- (y0 - yStart) * yPxSpace);

canvas.drawPath(path1, redlinePaint);

Path path2 = new Path();

path2.moveTo(rect.left + (x2 - xStart) * xPxSpace, rect.bottom

- (y2 - yStart) * yPxSpace);

path2.lineTo(rect.left + (x0 - xStart) * xPxSpace, rect.bottom

- (y0 - yStart) * yPxSpace);

canvas.drawPath(path2, redlinePaint);

Path path3 = new Path();

path3.moveTo(rect.left + (x3 - xStart) * xPxSpace, rect.bottom

- (y3 - yStart) * yPxSpace);

path3.lineTo(rect.left + (x0 - xStart) * xPxSpace, rect.bottom

- (y0 - yStart) * yPxSpace);

canvas.drawPath(path3, redlinePaint);

String xyz = "(" + x + "," + y + "," + z + ")";

// canvas.drawText(xyz,rect.left + (x0-xStart)*xPxSpace+20, rect.bottom

// - (y0-yStart)*yPxSpace-20, paintDegree);// 文字

canvas.drawText("(" + x + ",", rect.left + (x0 - xStart) * xPxSpace

+ 20, rect.bottom - (y0 - yStart) * yPxSpace - 20, paintX);// 文字

canvas.drawText(y + "", rect.left + (x0 - xStart) * xPxSpace + 70,

rect.bottom - (y0 - yStart) * yPxSpace - 20, paintY);// 文字

canvas.drawText("," + z + ")", rect.left + (x0 - xStart) * xPxSpace

+ 110, rect.bottom - (y0 - yStart) * yPxSpace - 20, paintZ);// 文字

canvas.drawLine(rect.left + (x1 - xStart) * xPxSpace, rect.bottom

- (y1 - yStart) * yPxSpace, rect.left + (x11 - xStart)

* xPxSpace, rect.bottom - (y11 - yStart) * yPxSpace,

greedlinePaint);// z=0

canvas.drawLine(rect.left + (x1 - xStart) * xPxSpace, rect.bottom

- (y1 - yStart) * yPxSpace, rect.left + (x22 - xStart)

* xPxSpace, rect.bottom - (y22 - yStart) * yPxSpace,

greedlinePaint);// z=0

canvas.drawLine(rect.left + (x3 - xStart) * xPxSpace, rect.bottom

- (y3 - yStart) * yPxSpace, rect.left + (x11 - xStart)

* xPxSpace, rect.bottom - (y11 - yStart) * yPxSpace,

greedlinePaint);// z=0

canvas.drawLine(rect.left + (x2 - xStart) * xPxSpace, rect.bottom

- (y2 - yStart) * yPxSpace, rect.left + (x22 - xStart)

* xPxSpace, rect.bottom - (y22 - yStart) * yPxSpace,

greedlinePaint);// z=0

canvas.drawLine(rect.left + (x3 - xStart) * xPxSpace, rect.bottom

- (y3 - yStart) * yPxSpace, rect.left + (x33 - xStart)

* xPxSpace, rect.bottom - (y33 - yStart) * yPxSpace,

greedlinePaint);// z=0

canvas.drawLine(rect.left + (x2 - xStart) * xPxSpace, rect.bottom

- (y2 - yStart) * yPxSpace, rect.left + (x33 - xStart)

* xPxSpace, rect.bottom - (y33 - yStart) * yPxSpace,

greedlinePaint);// z=0

}

/**

* 画圆

*

* @param yData

* @param xData

*/

private void drawCircle(Canvas canvas, Rect rect, int[] xData, int[] yData) {

if (xData == null || yData == null) {

return;

}

for (int i = 0; i < xData.length; i++) {

canvas.drawCircle(rect.left + (xData[i] - xStart) * xPxSpace,

rect.bottom - (yData[i] - yStart) * yPxSpace, 5,

circlePaint);

}

}

/**

* 绘制一个完整背景图形

*

* @param canvas

*            画布

* @param rect

*            区域

*/

public void drawExample(Canvas canvas, Rect rect) {

/** 绘制背景 */

canvas.drawRect(rect, paintBack);

// 需要根据矩形绘制出两条线 (即所谓的X、Y轴线)

int sx = rect.left, sy = rect.top, ex = rect.left, ey = rect.bottom;

canvas.drawLine(sx, sy, ex, ey, linePaint);// Y纵向的线段 左

/** sx2为表格起始点 */

int sx2 = rect.left, sy2 = rect.bottom, ex2 = rect.right, ey2 = rect.bottom;

canvas.drawLine(sx2, sy2, ex2, ey2, linePaint);// 横向的线段 下

int sx3 = rect.left, sy3 = rect.top, ex3 = rect.right, ey3 = rect.top;

canvas.drawLine(sx3, sy3, ex3, ey3, linePaint);// 上

int sx4 = rect.right, sy4 = rect.top, ex4 = rect.right, ey4 = rect.bottom;

canvas.drawLine(sx4, sy4, ex4, ey4, linePaint);// 右

/** X轴刻度间距 */

float spaceX = (rect.right - rect.left) / xNum;

for (int i = 0; i <= xNum; i++) {// 12是X轴共12个空隙

canvas.drawLine(rect.left + spaceX * i, rect.bottom, rect.left

+ spaceX * i, rect.bottom - 8, linePaint);// 刻度

canvas.drawText(xArr[i], rect.left + spaceX * i - 8,

rect.bottom + 25, paintDegree);// 文字

}

/** Y轴刻度间距 */

float spaceY = (rect.bottom - rect.top) / yNum;

for (int i = 0; i <= yNum; i++) {// 8是Y轴共8个空隙

canvas.drawLine(rect.left, rect.top + spaceY * i, rect.left + 8,

rect.top + spaceY * i, linePaint);// 刻度

canvas.drawText(yArr[i], rect.left - 35, rect.bottom - spaceY * i

+ 8, paintDegree);// 文字

}

/** 每点值的距离 */

xPxSpace = (rect.right - rect.left) / (xEnd - xStart);

/** 每点值的距离 */

yPxSpace = (rect.bottom - rect.top) / (yEnd - yStart);

if (isShowGraticule) {// 是否需要显示标线

// 50 zuo===555 you===355xia===20 shang

// 下面的值 (60、80、90、100 90、120、140、160 是标线值)

canvas.drawLine(rect.left, rect.bottom - (yMarkingOne - yStart)

* yPxSpace, rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom - (yMarkingOne - yStart) * yPxSpace, linePaint);// 3

canvas.drawLine(rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom, rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom - (yMarkingOne - yStart) * yPxSpace, linePaint);// 4

canvas.drawLine(rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom - (yMarkingOne - yStart) * yPxSpace,

rect.right, rect.top, linePaint);// 11

canvas.drawLine(rect.left, rect.bottom - (yMarkingOne - yStart)

* yPxSpace,

(rect.right - (xMarkingOne - xStart) * xPxSpace), rect.top,

linePaint);// 9

canvas.drawLine(rect.left, rect.bottom,

(rect.right - (xMarkingOne - xStart) * xPxSpace),

(yMarkingOne - yStart) * yPxSpace, linePaint);// 10

canvas.drawLine(rect.left + (xMarkingOne - xStart) * xPxSpace,

rect.bottom, (rect.right), (yMarkingOne - yStart)

* yPxSpace, linePaint);// 12

canvas.drawLine((rect.right - (xMarkingOne - xStart) * xPxSpace),

(yMarkingOne - yStart) * yPxSpace, (rect.right),

(yMarkingOne - yStart) * yPxSpace, linePaint);// 5

canvas.drawLine((rect.right - (xMarkingOne - xStart) * xPxSpace),

(yMarkingOne - yStart) * yPxSpace,

(rect.right - (xMarkingOne - xStart) * xPxSpace), rect.top,

linePaint);// 6

}

}

/** 获得一个字符串的高度 */

public static int getStringHeight(Paint paint, String str) {

int height = 0;

Rect rect = new Rect();

paint.getTextBounds(str, 0, str.length(), rect);// 用一个矩形去"套"字符串,获得能完全套住字符串的最小矩形

height = rect.height();// 字符串的高度

return height;

}

}