安卓开发,自定义view折线图的练习
效果图
1.自定义view
public class BrokenLineView extends View {
private float left;//折线图左边坐标
private float bottom;//折线图底部坐标
private float right;//折线图右边坐标
private float top;//折线图顶部坐标
private Context context;
private Canvas mCanvas;
private Path mPath;
private Paint linePaint;
private Paint mTextPaint;
public BrokenLineView(Context context) {
super(context);
}
public BrokenLineView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
initPaint();
initData();
}
private void initPaint(){
mPath = new Path();
linePaint = new Paint();
linePaint.setColor(Color.YELLOW);//线条的颜色
linePaint.setStrokeWidth(8);//线条的宽度
linePaint.setAntiAlias(true);//取消锯齿
linePaint.setStyle(Paint.Style.STROKE);//粗线
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
mTextPaint.setColor(Color.WHITE);
mCanvas = new Canvas();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();//锁定画布
drawXY(canvas);
drawXYelement(canvas);
drawLines(canvas);
drawBitmap(canvas);
}
/**
* 获取父控件尺寸
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
left = w*(1/16f);
right = w*(15/16f);
top = w*(1/16f);
bottom = w*(8/16f);
}
//画XY坐标轴
private void drawXY(Canvas canvas){
/**
* 连接三个坐标点
* 1(left,top) 2(left,bottom) 3(right,bottom)
*/
Log.i("123", "left: "+left+"top: "+top+"bottom: "+bottom);
mPath.moveTo(left,top);
mPath.lineTo(left,bottom);
mPath.lineTo(right,bottom);
//连接三个坐标
canvas.drawPath(mPath,linePaint);
//释放画布
canvas.restore();
}
//画坐标轴旁边的XY
private void drawXYelement(Canvas canvas){
canvas.save();
mTextPaint.setTextSize(36);//文字大小
//Y轴文字提示
mTextPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("Y",left+20,top,mTextPaint);
//X轴文字提示
mTextPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText("X",right,bottom+50,mTextPaint);
canvas.restore();
}
private List<PointF> pointFList = new ArrayList<>();
private String[] index_x = {"","周一","周二","周三","周四","周五","周六","周天"};
private int[] index_y = {0,1,2,3,4,5,6,7,8};
private float spaceX,spaceY;//横纵坐标间隔
private float maxX,maxY;//横纵数据最大值
private void initData(){
pointFList.add(new PointF(0.3F, 0.5F));
pointFList.add(new PointF(1F, 22.7F));
pointFList.add(new PointF(2F, 33.5F));
pointFList.add(new PointF(3F, 36.2F));
pointFList.add(new PointF(4F, 18.8F));
pointFList.add(new PointF(5F, 15.5F));
pointFList.add(new PointF(6F, 24.2F));
pointFList.add(new PointF(7F, 52.5F));
}
//画网格
private void drawLines(Canvas canvas){
canvas.save();
linePaint.setStrokeWidth(2);
int count = pointFList.size();
spaceX = (right-left)/count;
spaceY = (bottom-top)/count;
// 计算除数的值为数据长度减一,8个数据,7条线。
int divisor = count-1;
//计算X轴最大值
for (int i = 0; i < count; i++) {
if (maxX<pointFList.get(i).x){
maxX = pointFList.get(i).x;//X轴最大值
}
}
//计算X轴最近的能被Count整除的值
int remainderX = (int) maxX % divisor;
maxX = remainderX == 0 ? ((int) maxX) : divisor - remainderX + maxX;
//计算Y轴最大值
for (int i = 0; i < count; i++) {
if (maxY < pointFList.get(i).y){
maxY = pointFList.get(i).y;//y轴最大值
}
}
//计算Y轴最近的能被count整除的值
int remainderY = ((int) maxY) % divisor;
maxY = remainderY == 0 ? ((int) maxY) : divisor + remainderY + maxY;
//锁定画布并设定透明度为75%
int sc = canvas.saveLayerAlpha(0,0,canvas.getWidth(),canvas.getHeight(),75,Canvas.ALL_SAVE_FLAG);
// 绘制横纵线段
for (float y = bottom - spaceY; y > top; y -= spaceY) {
for (float x = left; x < right; x += spaceX) {
/*
* 绘制纵向线段
*/
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);
}
}
}
//还原画布
canvas.restoreToCount(sc);
int num = 0;//用于给X轴赋值
int num_y = 0;//用于给Y轴赋值
for (float y = bottom - spaceY; y > top; y -= spaceY) {
for (float x = left; x < right; x += spaceX) {
mTextPaint.setTextSize(28);
/*
* 绘制横轴刻度数值
*/
if (y == bottom - spaceY) {
canvas.drawText(""+index_x[num], x+8, bottom+top/2, mTextPaint);
}
/*
* 绘制纵轴刻度数值
* 简单来说就是,Y轴上的坐标点,X轴是恒定不变的,但是Y轴是变化的(buttom - 间距)+10的距离向上绘制
*/
if (x == left) {
canvas.drawText(""+index_y[num_y+1], left - (left/2), y + 10, mTextPaint);
}
num++;
}
num_y++;
}
}
private void drawBitmap(Canvas canvas){
/**
* 我们给我们的区域先绘制一个颜色模块,做法很简单,生成一个图片即可,然后透明度设置下
* Bitmap.createBitmap()
* 关于他的6个方法,可查看博客:http://www.cnblogs.com/wangxiuheng/p/4503610.html
*/
Log.i("123", "X: "+((int) (right - left - spaceX))+";Y:"+((int) (bottom - top - spaceY)));
Bitmap bitmap = Bitmap.createBitmap(((int) (right - left - spaceX)), ((int) (bottom - top - spaceY)), Bitmap.Config.ARGB_8888);
mCanvas.setBitmap(bitmap);
/**
* 为画布填充一个半透明的红色
* drawARGB(a,r,g,b)a:透明度 r:红色g:绿色b:蓝色
* */
mCanvas.drawARGB(55,255,0,0);
mPath.reset();//重置曲线
canvas.drawBitmap(bitmap,left,top+spaceY,null);
//绘制我们的坐标点
drawText(canvas);
}
public synchronized void setdata(List<PointF> mList, String signX, String signY, Activity activity){
if (null == mList || mList.size() == 0){
throw new IllegalArgumentException("没有数据展示");
}
if (mList.size()>10){
throw new IllegalArgumentException("数据太多建议使用散点图");
}
//设置数据并重绘视图
this.pointFList = mList;
this.context = activity;
invalidate();
}
private void drawText(Canvas canvas) {
Paint pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
pointPaint.setStyle(Paint.Style.FILL);//焦点的类型
pointPaint.setColor(Color.WHITE);//焦点的颜色
if(pointFList.size()==0){
Toast.makeText(context,"暂无折现数据",Toast.LENGTH_SHORT).show();
}else {
/*
* 生成Path和绘制Point
*/
for (int i = 0; i < pointFList.size(); i++) {
// 计算x坐标
float x = mCanvas.getWidth() / maxX * pointFList.get(i).x;
// 计算y坐标
float y = mCanvas.getHeight() / maxY * pointFList.get(i).y;
y = mCanvas.getHeight() - y;
// 绘制小点点
mCanvas.drawCircle(x, y, 6, pointPaint);
/*
* 如果是第一个点则将其设置为Path的起点
*/
if (i == 0) {
mPath.moveTo(x, y);
}
// 连接各点
mPath.lineTo(x, y);
}
// 设置PathEffect
linePaint.setPathEffect(new CornerPathEffect(10));
// 重置线条宽度
linePaint.setStrokeWidth(4);
// 将Path绘制到我们自定的Canvas上
mCanvas.drawPath(mPath, linePaint);
}
}
}
2.xml中引用
<com.hsg.brokenlinedemo.BrokenLineView
android:id="@+id/blv"
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#8B7500"/>
3.activity中添加数据
List<PointF> pointFs = new ArrayList<PointF>();
pointFs.add(new PointF(0.3F, 0.5F));
pointFs.add(new PointF(1F, 22.7F));
pointFs.add(new PointF(2F, 33.5F));
pointFs.add(new PointF(3F, 36.2F));
pointFs.add(new PointF(4F, 18.8F));
pointFs.add(new PointF(5F, 15.5F));
pointFs.add(new PointF(6F, 24.2F));
pointFs.add(new PointF(7F, 52.5F));
blv.setdata(pointFs, "X轴提示文字", "Y轴提示文字",MainActivity.this);