Android自定义view之天气折线图
最近公司一个项目需求,需要添加一个折线图,能够显示七天的天气信息。当然这个需求并不是很难,网上也有很多相关的例子,但是为了巩固下自定义view的基础,所以我决定还是自己写一个玩玩。不啰嗦,先上效果图(demo没有美化,比较简陋)
看了效果图,是不是感觉比较简单,麻雀虽小,但是五脏俱全,这里面囊括自定义view的核心。
先介绍下自定义view里面的几个核心方法,后面我们都有用到的。
OnMeasure 这个负责测量的,一般我习惯在这里计算自定义view需要的一些值,比如说间距,大小等。
OnDraw 听这个名字就知道是绘制了,也是这个demo的最重要的地方了。
分析
两点确定一条线,这个概念大概我们在读小学的时候老师就应该教过我们吧,所以我们绘制折线的时候也是要依据这个概念了。点是通过XY来确定的,这里X是比较简单确定,因为都是相同的间隔,难点就是Y了。
想要知道Y坐标也是很简单的,在七天温度中,我们可以知道最高温与最低温相差多少,然后也可以知道我们的绘制区域的高度,最后就可以得知一个温度所占的高度。然后用每一个温度去减去最低温,就可以得与最低温相差多少,然后就很轻松的知道这个温度的高度了。
声明需要的值
将一些常用的值写在上面是为了便于以后修改,万一哪天产品经理要你改下颜色什么的,一下就可以搞定了,不用到处去找。
/**
* view的总高度
*/
private int mViewHeight;
/**
* view的总宽度
*/
private int mViewWidth;
/**
* 温度字体大小
*/
private int mTempTextSize=22;
/**
* 温度字体颜色
*/
private int mTempTextColor=Color.GREEN;
/**
* 线的宽度
*/
private int mWeaLineWidth = 3;
/**
* 圆点的半径
*/
private int mWeaDotRadius = 5;
/**
* 画圆圈的画笔与画线的笔
*/
private Paint mDotPaint;
private Paint mLinePaint;
/**
* 画灰色线的笔与画温度的笔
*/
private Paint mGrayLinePaint;
private TextPaint mTempPaint;
/**
* 文字和点的间距
*/
private int mTextDotDistance = 20;
/**
* 坐标点文字偏移量
*/
private static final int POINT_TEXT_OFFSET = 10;
/**
* 最高温集合中温度差
*/
private float mHighsTempest;
/**
* 最低温集合中温度差
*/
private int mLowsTempest;
/**
* 最高温数组
*/
private List<Integer> mHighs;
/**
* 最低温数组
*/
private List<Integer> mLows;
/**
* 与顶部和底部的间距
*/
private final int mMarginTopAndrBottom=15;
/**
*每个点的间隔X轴
*/
private int mInterval;
/**
* 第一个点的X坐标
*/
private float mFristX;
/**
* 折线图高度(单个)
*/
private float mLineHeight;
/**
* 灰色线的间隔
*/
private int mSpace=200;
//高温线的颜色
private final static int LINE_COLOR_HIGH=Color.RED;
//低温线的颜色
private final static int LINE_COLOR_LOW=Color.BLUE;
绘制线
因为七个点,所以只要画6条线就OK了.
private void drawLine(Canvas canvas) {
float highsBaseY=mLineHeight/mHighsTempest;//最高温中每隔一度对应相隔多少y坐标
float lowsBaseY=mLineHeight/mLowsTempest;//最低温中每隔一度对应相隔多少y坐标
float y1,y2=0f;//y1起点y坐标,y2 终点y坐标
float x1,x2=0f;
//绘制高温
for (int i=0;i<mHighs.size()-1;i++){
x1=mFristX+mInterval*i;
x2=mFristX+mInterval*(i+1);
y1=mHighs.get(i)-mHighsLowest;
y1=highsBaseY*y1-(mMarginTopAndrBottom*3);
y1=mLineHeight-y1;
y2=mHighs.get(i+1)-mHighsLowest;
y2=highsBaseY*y2-(mMarginTopAndrBottom*3);
y2=mLineHeight-y2;
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.drawLine(x1,y1,x2,y2,mLinePaint);
}
//绘制低温
mLinePaint.setColor(Color.BLUE);
for (int i=0;i<mLows.size()-1;i++){
x1=mFristX+mInterval*i;
x2=mFristX+mInterval*(i+1);
y1=mLows.get(i)-mLowsLowsest;
y1=lowsBaseY*y1-(mMarginTopAndrBottom*3);
y1=mLineHeight-y1+mSpace;
y2=mLows.get(i+1)-mLowsLowsest;
y2=lowsBaseY*y2-(mMarginTopAndrBottom*3);
y2=mLineHeight-y2+mSpace;
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.drawLine(x1,y1,x2,y2,mLinePaint);
}
}
绘制圆圈
private void drawDot(Canvas canvas) {
float highsBaseY=mLineHeight/mHighsTempest;//最高温中每隔一度对应相隔多少y坐标
float lowsBaseY=mLineHeight/mLowsTempest;//最低温中每隔一度对应相隔多少y坐标
// Log.e("smile","highsBaseY "+highsBaseY+" lowsBaseY"+lowsBaseY);
float y=0f;
float x=0f;
for (int i = 0; i < mHighs.size(); i++) {
y=mHighs.get(i)-mHighsLowest;
x=mFristX+mInterval*i;
y=highsBaseY*y-(mMarginTopAndrBottom*3);
y=mLineHeight-y;
canvas.drawCircle(x,y,mWeaDotRadius,mDotPaint);
}
for (int i = 0; i < mLows.size(); i++) {
// Log.e("smile","lowset "+mLowsLowsest+" "+mLows.get(i)+" mlineHeight "+mLineHeight);
y=mLows.get(i)-mLowsLowsest;
y=lowsBaseY*y-(mMarginTopAndrBottom*3);
y=mLineHeight-y+mSpace;
canvas.drawCircle(mFristX+mInterval*i,y,mWeaDotRadius,mDotPaint);
}
}
绘制温度
记住一个是在上面,一个是在下面,
private void drawTemp(Canvas canvas){
float baseY=mLineHeight/mHighsTempest;//每隔一度对应相隔多少y坐标
float lowsBaseY=mLineHeight/mLowsTempest;//最低温中每隔一度对应相隔多少y坐标
float y=0f;
float x=0f;
for (int i = 0; i < mHighs.size(); i++) {
y=mHighs.get(i)-mHighsLowest;
y=baseY*y-(mMarginTopAndrBottom*3);
y=mLineHeight-y-mTextDotDistance;
x=mFristX+mInterval*i-POINT_TEXT_OFFSET;
canvas.drawText(String.valueOf(mHighs.get(i)),x,y,mTempPaint);
}
for (int i = 0; i < mHighs.size(); i++) {
y=mLows.get(i)-mLowsLowsest;
y=lowsBaseY*y-(mMarginTopAndrBottom*3);
y=mLineHeight-y+mSpace+mTextDotDistance+10;
x=mFristX+mInterval*i-POINT_TEXT_OFFSET;
canvas.drawText(String.valueOf(mLows.get(i)),x,y,mTempPaint);
}
}
最后贴上这个类的源码:传送门
代码都有详细的注释。周五万岁,,,