自定义view折线图.docx
《自定义view折线图.docx》由会员分享,可在线阅读,更多相关《自定义view折线图.docx(54页珍藏版)》请在冰豆网上搜索。
自定义view折线图
自定义view—折线图
绘制折线图预览图
绘制这个折线图需要都需要哪些步骤?
一、如何绘制X和Y轴。
注意:
绘制线用到的是path,而绘制X和Y轴,我们需要知道三个坐标,这里我们用的是canvas.drawPath(mPath,linePaint);
1、我们来分析下,我们想知道三个坐标,那么这三个坐标是多少呢,我们该怎么计算呢?
答:
这里,我是在onSizeChanged()方法中获取到了父类控件的宽度,然后把宽度分成16份,例如,下方的上下左右四个分别如下:
lift=viewSize*(1/16f);
top=viewSize*(1/16f);
right=viewSize*(15/16f);
buttom=viewSize*(8/16f);
2、这三个坐标我们有了,那就好办了,我们根据这四个参数值,就可以知道我们上面三个坐标点的坐标,在draw()方法中,连接这三个点即可:
privatevoiddrawXY(Canvascanvas){
/*
*第三步,我们来通过viewSize尺寸来获取三个坐标点
*第一个(X,Y)--(lift,top)
*第二个(X,Y)--(lift,button)
*第三个个(X,Y)--(right,buttom)
**/
mPath.moveTo(lift,top);
mPath.lineTo(lift,buttom);
mPath.lineTo(right,buttom);
//使用Path链接这三个坐标
canvas.drawPath(mPath,linePaint);
//释放画布
canvas.restore();
}
3、我们最后,在X,Y轴写个文字,那么我们需要知道X,Y这两个文字的坐标是多少?
如图:
答:
因为我们已经知道lift,right,top,buttom。
其实我们就可计算出来他们的坐标了。
其实Y轴的坐标只是向右移动一点即可(lift+num,top),x的坐标向下移动一点即可(right,top+num),其中num是你移动多少。
自己可以合理调试
privatevoiddrawXYelement(Canvascanvas){
//锁定画布
canvas.save();
mTextPaint.setTextSize(36);//文字大小
/*
*Y轴文字提示
*drawText(String,x,y,TextPaint)
*(lift,top)
**/
mTextPaint.setTextAlign(Paint.Align.LEFT);//左对齐
canvas.drawText("Y",lift+20,top,mTextPaint);
/*
*X轴文字提示
*drawText(String,right,buttom,TextPaint)
**/
mTextPaint.setTextAlign(Paint.Align.RIGHT);//右对齐
canvas.drawText("X",right,buttom+50,mTextPaint);
//释放画布
canvas.restore();
}
我们在main的xml引用此类
<.polylinedemo.XYView01
android:
id="@+id/My_XYView04"
android:
layout_width="wrap_content"
android:
layout_height="500dp"
android:
background="#8B7500"
/>
编译一下效果:
4、附上全部代码
package.polylinedemo;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.graphics.Paint;
importandroid.graphics.Path;
importandroid.text.TextPaint;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.View;
/**
*CreatedbyENZon2016/11/25.
*绘制自定义view折线图
*第一步:
绘制X和Y轴,那么我们需要什么准备呢?
*/
publicclassXYView01extendsView{
privateintviewSize;//获取空间的尺寸,也就是我们布局的尺寸大小(不知道理解的是否正确)
privatePaintlinePaint;//线条画笔和点画笔
privatePathmPath;//路径对象
privateTextPaintmTextPaint;//文字画笔
floatlift;
floattop;
floatright;
floatbuttom;
floatPathY_X;
floatPathY_Y;
floatPathX_X;
floatPathX_Y;
publicXYView01(Contextcontext,AttributeSetattrs){
super(context,attrs);
//第一步,初始化对象
linePaint=newPaint();
linePaint.setColor(Color.YELLOW);//线条的颜色
linePaint.setStrokeWidth(8);//线条的宽度
linePaint.setAntiAlias(true);//取消锯齿
linePaint.setStyle(Paint.Style.STROKE);//粗线
//初始化Path
mPath=newPath();
mTextPaint=newTextPaint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG|Paint.LINEAR_TEXT_FLAG);
mTextPaint.setColor(Color.WHITE);
}
publicXYView01(Contextcontext){
super(context);
}
@Override
protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
//在我们没学习测量控件之前强制宽高一致
super.onMeasure(widthMeasureSpec,widthMeasureSpec);
}
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
//第二步骤,我们在这里获取每个用到的坐标点和尺寸
viewSize=w;//获取空间的尺寸,
Log.i("Text","viewSize:
"+viewSize);
//这个是我们上下左右需要用到的坐标点
lift=viewSize*(1/16f);
top=viewSize*(1/16f);
right=viewSize*(15/16f);
buttom=viewSize*(8/16f);
}
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
//锁定画布
canvas.save();
//定义一个绘制X,Y轴的方法
drawXY(canvas);
//绘制X和Y轴上的提示文字
drawXYelement(canvas);
}
privatevoiddrawXY(Canvascanvas){
/*
*第三步,我们来通过viewSize尺寸来获取三个坐标点
*第一个(X,Y)--(lift,top)
*第二个(X,Y)--(lift,button)
*第三个个(X,Y)--(right,buttom)
**/
mPath.moveTo(lift,top);
mPath.lineTo(lift,buttom);
mPath.lineTo(right,buttom);
//使用Path链接这三个坐标
canvas.drawPath(mPath,linePaint);
//释放画布
canvas.restore();
}
privatevoiddrawXYelement(Canvascanvas){
//锁定画布
canvas.save();
mTextPaint.setTextSize(36);//文字大小
/*
*Y轴文字提示
*drawText(String,x,y,TextPaint)
*(lift,top)
**/
mTextPaint.setTextAlign(Paint.Align.LEFT);//左对齐
canvas.drawText("Y",lift+20,top,mTextPaint);
/*
*X轴文字提示
*drawText(String,right,buttom,TextPaint)
**/
mTextPaint.setTextAlign(Paint.Align.RIGHT);//右对齐
canvas.drawText("X",right,buttom+50,mTextPaint);
//释放画布
canvas.restore();
}
}
1、我们绘制X和Y轴区域的子网格,我们需要知道他们范围?
Y轴上的最大范围=(buttom-top);
X轴的最大范围=(right-lift);
2、在这个范围我们需要分为多少个端即有几个数据?
每一段间距事是多少?
//假如我们有八条数据
intcount=pointFs.size();
//计算横纵坐标刻度间隔
spaceY=(buttom-top)/count;
spaceX=(right-lift)/count;
3、最大值和最小值是多少?
//计算横轴数据最大值
maxX=0;
for(inti=0;iif(maxXmaxX=pointFs.get(i).x;//X轴最大坐标
}
}
Log.i("Text","maxX:
--"+maxX);
//计算横轴最近的能被count整除的值
intremainderX=((int)maxX)%divisor;
maxX=remainderX==0?
((int)maxX):
divisor-remainderX+((int)maxX);
//计算纵轴数据最大值
maxY=0;
for(inti=0;iif(maxYmaxY=pointFs.get(i).y;
}
}
Log.i("Text","maxY:
--"+maxY);
//计算纵轴最近的能被count整除的值
intremainderY=((int)maxY)%divisor;
Log.i("Text","remainderY:
--"+remainderY);
4、既然我们已经知道了最大值和最小值,也知道了间距,那么我么开始绘制,通过for循环来绘制Y轴,每绘制每一个Y轴的点,都会把X轴与之相交的点全部绘制。
(自己可以在本子上画画图就容易理解了)例如下图
//锁定画布并设置画布透明度为75%
intsc=canvas.saveLayerAlpha(0,0,canvas.getWidth(),canvas.getHeight(),75,Canvas.ALL_SAVE_FLAG);
//绘制横纵线段
for(floaty=buttom-spaceY;y>top;y-=spaceY){
Log.i("Text","y"+y);
for(floatx=lift;xLog.i("Text","x"+x);
/*
*绘制纵向线段
*/
if(y==top+spaceY){
canvas.drawLine(x,y,x,y+spaceY*(count-1),linePaint);
}
/*
*绘制横向线段
*/
if(x==right-spaceX){
canvas.drawLine(x,y,x-spaceX*(count-1),y,linePaint);
}
}
}
5、全部代码,只是多了一个方法drawLines(canvas);
package.polylinedemo;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.graphics.Paint;
importandroid.graphics.Path;
importandroid.graphics.PointF;
importandroid.text.TextPaint;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.View;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.Random;
/**
*CreatedbyENZon2016/11/25.
*绘制自定义view折线图
*第一步:
绘制X和Y轴,那么我们需要什么准备呢?
*/
publicclassXYView02extendsView{
privateintviewSize;//获取空间的尺寸,也就是我们布局的尺寸大小(不知道理解的是否正确)
privatePaintlinePaint;//线条画笔和点画笔
privatePathmPath;//路径对象
privateTextPaintmTextPaint;//文字画笔
privateListpointFs=newArrayList<>();//数据列表
privatefloat[]rulerX,rulerY;//xy轴向刻度
//上下左右坐标点
privatefloatlift;
privatefloattop;
privatefloatright;
privatefloatbuttom;
//Y轴文字坐标点
privatefloatPathY_X;
privatefloatPathY_Y;
//X轴文字坐标点
privatefloatPathX_X;
privatefloatPathX_Y;
privatefloatmaxX;//x轴最大值
privatefloatmaxY;//Y轴最大值
privatefloatspaceX,spaceY;//刻度间隔
publicXYView02(Contextcontext,AttributeSetattrs){
super(context,attrs);
//第一步,初始化对象
linePaint=newPaint();
linePaint.setColor(Color.YELLOW);//线条的颜色
linePaint.setStrokeWidth(8);//线条的宽度
linePaint.setAntiAlias(true);//取消锯齿
linePaint.setStyle(Paint.Style.STROKE);//粗线
//初始化Path
mPath=newPath();
mTextPaint=newTextPaint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG|Paint.LINEAR_TEXT_FLAG);
mTextPaint.setColor(Color.WHITE);
//模拟数据
initData();
}
publicXYView02(Contextcontext){
super(context);
}
@Override
protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
//在我们没学习测量控件之前强制宽高一致
super.onMeasure(widthMeasureSpec,widthMeasureSpec);
}
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
//第二步骤,我们在这里获取每个用到的坐标点和尺寸
viewSize=w;//获取空间的尺寸,
Log.i("Text","viewSize:
"+viewSize);
//这个是我们上下左右需要用到的坐标点
lift=viewSize*(1/16f);
top=viewSize*(1/16f);
right=viewSize*(15/16f);
buttom=viewSize*(8/16f);
//下面是绘制X,Y轴提示文字
/*
*Y轴(PathY_X,PathY_Y)
**/
PathY_X=viewSize*2/16;
PathY_Y=viewSize*1/16;
/*
*X轴(PathX_X,PathX_Y)
**/
PathX_X=viewSize*15/16f;
PathX_Y=viewSize*9/16f;
}
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
//锁定画布
canvas.save();
//定义一个绘制X,Y轴的方法
drawXY(canvas);
//绘制X和Y轴上的提示文字
drawXYelement(canvas);
}
privatevoidinitData(){
Randomrandom=newRandom();
pointFs=newArrayList();
for(inti=0;i<8;i++){
PointFpointF=newPointF();
pointF.x=(float)(random.nextInt(100)*i);
pointF.y=(float)(random.nextInt(100)*i);
pointFs.add(pointF);
}
}
privatevoiddrawXY(Canvascanvas){
/*
*第三步,我们来通过viewSize尺寸来获取三个坐标点
*第一个(X,Y)--(lift,top)
*第二个(X,Y)--(lift,button)
*第三个个(X,Y)--(right,buttom)
**/
mPath.moveTo(lift,top);
mPath.lineTo(lift,buttom);
mPath.lineTo(right,buttom);
//使用Path链接这三个坐标
canvas.drawPath(mPath,linePaint);
//----------------------------我们在这里添加一个绘制网格的方法----------------------------------------
drawLines(canvas);
//释放画布
canvas.restore();
}
privatevoiddrawLines(Canvascanvas){
//重置线条画笔,因为是细线,所有我这里设置了2。
linePaint.setStrokeWidth
(2);
//假如我们有八条数据
intcount=pointFs.size();
//计算横纵坐标刻度间隔
spaceY=(buttom-top)/count;
spaceX=(right-lift)/count;
Log.i("Text","spaceY:
--"+spaceY);
Log.i("Text","spaceX:
--"+spaceX);
//计算除数的值为数据长度减一,8个数据,7条线。
intdivisor=count-1;
Log.i("Text","divisor:
--"+divisor);
//计算横轴数据最大值
maxX=0;
for(inti=0;iif(maxXmaxX=pointFs.get(i).x;//X轴最大坐标
}
}
Log.i("Text","maxX:
--"+maxX);
//计算横轴最近的能被count整除的值
intremainderX=((int)maxX)%divisor;
maxX=remainderX==0?
((int)ma