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);
}
}
最後貼上這個類的源碼:傳送門
代碼都有詳細的註釋。週五萬歲,,,