前言:
在接触Android这么长时间,看到很多大牛都在和大家分享自己的知识,深有体会,刚好前段时间写了一个Demo,在此分享给大家。
下面就直接进入主题:
1.绘制的逻辑:
首先绘制一个矩形,然后获取矩形长、宽各自的起始位置且划分为n等份,就成了带刻度尺的正方形,然后根据长、宽划分等份的坐标点及正方体的角度,用drawLine()方法绘制线,最后就成了带刻度尺的正方体。
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;
}
}