最近公司一个项目需求,需要添加一个折线图,能够显示七天的天气信息。当然这个需求并不是很难,网上也有很多相关的例子,但是为了巩固下自定义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 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); } }最后贴上这个类的源码:传送门
代码都有详细的注释。周五万岁,,,