继续来一片简单的自定义View,折线图的自定义。
每天来一篇,进步无极限。愚公移山也要由易到难的,这次就没写xml文件的自定义属性:
public DefineLineView(Context context) {
super(context);
}
public DefineLineView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DefineLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
然后还是重写onMeasure方法:
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (MeasureSpec.EXACTLY == widthMode) {
width = widthSize;
} else {
throw new IllegalArgumentException("width is exactly mode!");
}
if (MeasureSpec.EXACTLY == heightMode) {
height = heightSize;
} else {
throw new IllegalArgumentException("height is exactly mode!");
}
setMeasuredDimension(width, height);
由于想省点事,就直接用EXACTLY ,没有去管atmost,无关紧要,
关键在ondraw方法里面比较费事:
@Override
protected void onDraw(Canvas canvas) {
Paint mPaint = new Paint();
mPaint.setTextSize(textFontSize);
mPaint.setColor(Color.RED);
/**
* 画Y轴
*/
int[] pointY = new int[textY.length];//保存y轴文字的坐标
//计算每个刻度的间距
int discY = (int) ((height - textFontSize * textY.length) / textY.length);
//测量文字的高度
Paint.FontMetrics fm = mPaint.getFontMetrics();
int yheight = (int) Math.ceil(fm.descent - fm.ascent);
for (int i = 0; i < textY.length; i++) {
canvas.drawText(textY[i], 0, discY * i + yheight, mPaint);
pointY[i] = discY * i + yheight;
}
/**
* 画X轴
*/
int[] pointX = new int[textX.length];//保存y轴文字的坐标
int offset = 50;
//计算每个刻度的距离
int discX = (int) ((width - textFontSize * textX.length) / textX.length);
for (int i = 0; i < textX.length; i++) {
canvas.drawText(textX[i], i * discX + textFontSize + offset, height - yheight - offset, mPaint);
pointX[i] = (int) (i * discX + textFontSize + offset);
}
/**
* 画点
*/
mPaint.setColor(Color.DKGRAY);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
int radious = 10;
Paint linePaint = new Paint();
linePaint.setColor(Color.DKGRAY);
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(5);
for (int i = 0; i < textX.length; i++) {
if (mapParams == null) {
throw new IllegalArgumentException("map 不能为空");
}
canvas.drawCircle(pointX[i], pointY[mapParams.get(i)], radious, mPaint);
if (i > 0) {
canvas.drawLine(pointX[i - 1], pointY[mapParams.get(i - 1)], pointX[i], pointY[mapParams.get(i)], linePaint);
}
}
}
首先画Y轴,在画Y轴的时候定义了一个数组来保存对应的坐标:
/**
* 画Y轴
*/
int[] pointY = new int[textY.length];//保存y轴文字的坐标
//计算每个刻度的间距
int discY = (int) ((height - textFontSize * textY.length) / textY.length);
//测量文字的高度
Paint.FontMetrics fm = mPaint.getFontMetrics();
int yheight = (int) Math.ceil(fm.descent - fm.ascent);
for (int i = 0; i < textY.length; i++) {
canvas.drawText(textY[i], 0, discY * i + yheight, mPaint);
pointY[i] = discY * i + yheight;
}
然后同样画X轴的时候,也要定义一个数组来保存X轴的坐标,
/**
* 画X轴
*/
int[] pointX = new int[textX.length];//保存y轴文字的坐标
int offset = 50;
//计算每个刻度的距离
int discX = (int) ((width - textFontSize * textX.length) / textX.length);
for (int i = 0; i < textX.length; i++) {
canvas.drawText(textX[i], i * discX + textFontSize + offset, height - yheight - offset, mPaint);
pointX[i] = (int) (i * discX + textFontSize + offset);
}
下面就是画点,首先在MainActivity里面定义了一个Map来保存要画的点,通过在View设置的方法把Map传进来。
/**
* 设置Y轴的数据
*
* @param textY
*/
public void setTextY(String[] textY) {
this.textY = textY;
}
/**
* 设置X轴的数据
*
* @param textX
*/
public void setTextX(String[] textX) {
this.textX = textX;
}
/**
* 设置Map
*
* @param mapParams
*/
public void setMapParams(Map<Integer, Integer> mapParams) {
this.mapParams = mapParams;
}
然后就开始画点和画折线:
/**
* 画点
*/
mPaint.setColor(Color.DKGRAY);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
int radious = 10;
Paint linePaint = new Paint();
linePaint.setColor(Color.DKGRAY);
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(5);
for (int i = 0; i < textX.length; i++) {
if (mapParams == null) {
throw new IllegalArgumentException("map 不能为空");
}
canvas.drawCircle(pointX[i], pointY[mapParams.get(i)], radious, mPaint);
if (i > 0) {
canvas.drawLine(pointX[i - 1], pointY[mapParams.get(i - 1)], pointX[i], pointY[mapParams.get(i)], linePaint);
}
}
最后在MainActivity里面设置下数据就ok了:
private String[] textY = {"50k", "40k", "30k", "20K", "10k"};
private String[] textX = {"1", "2", "3", "4", "5", "6", "7"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DefineLineView lineView = (DefineLineView) findViewById(R.id.lineView);
lineView.setTextY(textY);
lineView.setTextX(textX);
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < textX.length; i++) {
map.put(i, (int) (Math.random() * 5));
}
lineView.setMapParams(map);
}
贴一下Xml文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<com.example.shuiai.defineline.DefineLineView
android:id="@+id/lineView"
android:layout_width="match_parent"
android:layout_height="300dp" />
</LinearLayout>
贴下View的完整代码:
public class DefineLineView extends View {
/**
* view的宽
*/
private int width;
/**
* View的高
*/
private int height;
/**
* 存放Y轴文字的数组
*/
private String[] textY;
/**
* 存放X轴文字的数组
*/
private String[] textX;
/**
* 文字大小
*/
private float textFontSize = 40;
/**
* 设置Map
*
* @param context
*/
private Map<Integer, Integer> mapParams;
public DefineLineView(Context context) {
super(context);
}
public DefineLineView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DefineLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (MeasureSpec.EXACTLY == widthMode) {
width = widthSize;
} else {
throw new IllegalArgumentException("width is exactly mode!");
}
if (MeasureSpec.EXACTLY == heightMode) {
height = heightSize;
} else {
throw new IllegalArgumentException("height is exactly mode!");
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
Paint mPaint = new Paint();
mPaint.setTextSize(textFontSize);
mPaint.setColor(Color.RED);
/**
* 画Y轴
*/
int[] pointY = new int[textY.length];//保存y轴文字的坐标
//计算每个刻度的间距
int discY = (int) ((height - textFontSize * textY.length) / textY.length);
//测量文字的高度
Paint.FontMetrics fm = mPaint.getFontMetrics();
int yheight = (int) Math.ceil(fm.descent - fm.ascent);
for (int i = 0; i < textY.length; i++) {
canvas.drawText(textY[i], 0, discY * i + yheight, mPaint);
pointY[i] = discY * i + yheight;
}
/**
* 画X轴
*/
int[] pointX = new int[textX.length];//保存y轴文字的坐标
int offset = 50;
//计算每个刻度的距离
int discX = (int) ((width - textFontSize * textX.length) / textX.length);
for (int i = 0; i < textX.length; i++) {
canvas.drawText(textX[i], i * discX + textFontSize + offset, height - yheight - offset, mPaint);
pointX[i] = (int) (i * discX + textFontSize + offset);
}
/**
* 画点
*/
mPaint.setColor(Color.DKGRAY);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
int radious = 10;
Paint linePaint = new Paint();
linePaint.setColor(Color.DKGRAY);
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(5);
for (int i = 0; i < textX.length; i++) {
if (mapParams == null) {
throw new IllegalArgumentException("map 不能为空");
}
canvas.drawCircle(pointX[i], pointY[mapParams.get(i)], radious, mPaint);
if (i > 0) {
canvas.drawLine(pointX[i - 1], pointY[mapParams.get(i - 1)], pointX[i], pointY[mapParams.get(i)], linePaint);
}
}
}
/**
* 设置Y轴的数据
*
* @param textY
*/
public void setTextY(String[] textY) {
this.textY = textY;
}
/**
* 设置X轴的数据
*
* @param textX
*/
public void setTextX(String[] textX) {
this.textX = textX;
}
/**
* 设置Map
*
* @param mapParams
*/
public void setMapParams(Map<Integer, Integer> mapParams) {
this.mapParams = mapParams;
}
}
有木有很简单,很简单。