前几天有个需求,就是传入一串坐标,然后绘制统计图,经过百度发现,网上的统计图太高大上了,所以自己写了一个简单的统计图。第一次写,不知道是不是合乎规范,以后慢慢调整。
先是效果图:
直接贴代码吧:
package com.wscq.testlinechart;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class LineChartView extends View {
/** 原点的x,y */
private int originX, originY;
/** 箭头终点的x,y */
private int upperLimitX, upperLimitY;
/** 最后一个分割线和箭头之间的距离 */
private int unoccupiedX, unoccupiedY;
/** 分成几个区域 */
private int splitXNum, splitYNum;
/** 每一格的单位 */
private int splitXLength, splitYLength;
/** 分割线长度 */
private int splitLineLength;
/** 坐标字的大小 */
private int textSize;
/** 坐标点 */
private List<Point> points;
private Canvas canvas;
public LineChartView(Context context) {
super(context);
}
public LineChartView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
initCoord(this.getMeasuredWidth(), this.getMeasuredHeight());
}
/**
* 传入宽高,用来计算坐标的大体位置
*
* @param width
* @param height
*/
private void initCoord(int width, int height) {
originX = (int) (0.09375 * width);// 30;
originY = (int) (0.86 * height);// 350
upperLimitX = (int) (0.90625 * width);// 290
upperLimitY = (int) (0.07444 * height);// 30
unoccupiedX = 15;
unoccupiedY = 10;
splitXNum = 10;
splitYNum = 10;
splitLineLength = 5;
splitXLength = splitYLength = 10;
textSize = 25;
points = new ArrayList<>();
}
public void setPoints(List<Point> points) {
this.points = points;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
// 设置字体大小
paint.setTextSize(textSize);
// 设置画出的线的 粗细程度
paint.setStrokeWidth(3);
// 画坐标轴
drawXY(canvas, paint);
this.canvas = canvas;
drawLineChart();
super.onDraw(canvas);
}
public void drawLineChart() {
Paint paint = new Paint();
// 设置画出的线的 粗细程度
paint.setStrokeWidth(3);
// 画弧线
paint.setAntiAlias(true);// 设置画笔无锯齿
paint.setStyle(Paint.Style.STROKE);// 设置空心
for (int i = 0; i < points.size() - 1; i++) {
int x1 = computeX(points.get(i).x);
int y1 = computeY(points.get(i).y);
int x2 = computeX(points.get(i + 1).x);
int y2 = computeY(points.get(i + 1).y);
// 弧线所在矩形,圆弧起始角度,圆弧角度,是否显示半径连线,绘制时候所用的画笔
canvas.drawLine(x1, y1, x2, y2, paint);
}
}
/**
* 计算x坐标的位置
*
* @param x
* 实际x坐标
* @return x在屏幕上的像素位置
*/
private int computeX(int x) {
BigDecimal bigX = new BigDecimal(x);
BigDecimal bigSplitXLength = new BigDecimal(splitXLength);
MathContext mc = new MathContext(2, RoundingMode.HALF_DOWN);
BigDecimal RangeX = new BigDecimal(upperLimitX - unoccupiedX - originX);
BigDecimal EachX = RangeX.divide(new BigDecimal(splitXNum), mc);
BigDecimal coordinateValueX = EachX.multiply(bigX
.divide(bigSplitXLength));
return coordinateValueX.intValue() + originX;
}
/** 计算y坐标的位置 */
private int computeY(int y) {
BigDecimal bigY = new BigDecimal(y);
BigDecimal bigSplitYLength = new BigDecimal(splitYLength);
// 设置计算精度
MathContext mc = new MathContext(2, RoundingMode.HALF_DOWN);
// 整个量程所代表的像素值
BigDecimal RangeY = new BigDecimal(originY - upperLimitY - unoccupiedY);
// 每个格子所代表的像素值
BigDecimal EachY = RangeY.divide(new BigDecimal(splitYNum), mc);
// 先求出y坐标代表几格,然后用单位长度乘之,求出y轴距离圆点的像素
BigDecimal coordinateValueY = EachY.multiply(bigY.divide(
bigSplitYLength, mc));
// 实际在手机屏幕上的坐标
return originY - coordinateValueY.intValue();
}
/** 画坐标系 */
private void drawXY(Canvas canvas, Paint paint) {
// 画纵坐标
canvas.drawLine(originX, upperLimitY, originX, originY, paint);
int intervalY = (originY - upperLimitY - unoccupiedY) / 10;
for (int i = 0; i < splitYNum; i++) {
// 画刻度标记
canvas.drawLine(originX, originY - i * intervalY, originX
+ splitLineLength, originY - i * intervalY, paint);
// 写量程
if (i != 0) {
canvas.drawText(i * 10 + "", originX - textSize - textSize / 3,
originY - i * intervalY + textSize / 2, paint);
}
}
// 纵坐标尽头的箭头
canvas.drawLine(originX, upperLimitY, originX - splitLineLength,
upperLimitY + 2 * splitLineLength, paint);
canvas.drawLine(originX, upperLimitY, originX + splitLineLength,
upperLimitY + 2 * splitLineLength, paint);
// 画横坐标
canvas.drawLine(originX, originY, upperLimitX, originY, paint);
int intervalX = (upperLimitX - originX - unoccupiedX) / 10;
for (int i = 0; i < splitXNum; i++) {
// 画刻度标记
canvas.drawLine(originX + i * intervalX, originY, originX + i
* intervalX, originY - splitLineLength, paint);
// 写量程
canvas.drawText(i * 10 + "",
originX + i * intervalX - textSize / 2, originY
+ (int) (textSize * 1.3), paint);
}
// 横坐标尽头的箭头
canvas.drawLine(upperLimitX, originY,
upperLimitX - 2 * splitLineLength, originY - splitLineLength,
paint);
canvas.drawLine(upperLimitX, originY,
upperLimitX - 2 * splitLineLength, originY + splitLineLength,
paint);
}
}
上面是一个自定义view,调用时候使用如下方法既可:
package com.wscq.testlinechart;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
LineChartView lcv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lcv = (LineChartView) findViewById(R.id.lcv);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Random random = new Random();
List<Point> points = new ArrayList<Point>();
Point p = null;
for (int i = 0; i < 90; i++) {
p = new Point();
p.x = i;
p.y = random.nextInt(91);
points.add(p);
}
lcv.setPoints(points);
lcv.invalidate();
}
});
}
}
视图比较简单,就是一个按钮和一个图,然后这个统计图精度不是很高,整型还行,别的容易有误差。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<com.wscq.testlinechart.LineChartView
android:id="@+id/lcv"
android:layout_width="400dp"
android:layout_height="400dp"
android:text="@string/hello_world" />
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lcv" />
</RelativeLayout>