效果圖如下:
剛開始嘗試用第三方畫曲線的框架來畫效果圖,後來發現曲線間的陰影當有負數的度數的時候畫不出來,而且不需要點擊放大、點點可點的效果,用框架顯得很臃腫,所以最後用自定義View來畫的折線圖。自定義畫折線圖的大致思路:這個圖是有多個四邊形組成的(4個點連接起來就是一個四邊形),兩邊延伸:添加四個多餘的點,將左右的邊距設置成負數即可。
代碼如下:
public class WeatherChartView extends View {
/**
* x軸集合
*/
private float mXAxis[] ;
/**
* 白天y軸集合
*/
private float mYAxisDay[] ;
/**
* 夜間y軸集合
*/
private float mYAxisNight[] ;
/**
* x,y軸集合數
*/
private int LENGTH ;
/**
* 白天溫度集合
*/
private int mTempDay[] ;
/**
* 夜間溫度集合
*/
private int mTempNight[] ;
/**
* 控件高
*/
private int mHeight;
/**
* 字體大小
*/
private float mTextSize;
/**
* 圓半徑
*/
private float mRadius ;
/**
* 圓半徑今天
*/
private float mRadiusToday ;
/**
* 文字移動位置距離
*/
private float mTextSpace ;
/**
* 線的大小
*/
private float mStokeWidth ;
/**
* 白天折線顏色
*/
private int mColorDay = Color.parseColor("#ffffff");
/**
* 夜間折線顏色
*/
private int mColorNight = Color.parseColor("#ffffff");;
/**
* 字體顏色
*/
private int mTextColor = Color.parseColor("#ffffff");;
/**
* 屏幕密度
*/
private float mDensity;
/**
* 控件邊的空白空間
*/
private float mSpace;
@SuppressWarnings("deprecation")
public WeatherChartView(Context context, AttributeSet attrs) {
super(context, attrs);
mDensity = getResources().getDisplayMetrics().density;
mRadius = 3 * mDensity;
mRadiusToday = 3 * mDensity;
//mSpace = 3 * mDensity;
mTextSpace = 10 * mDensity;
mStokeWidth = 2 * mDensity;
mTextSize = BreakRuleTools.dip2px(context, 12);
}
public WeatherChartView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mHeight == 0) {
// 設置控件高度,x軸集合
setHeightAndXAxis();
}
// 計算y軸集合數值
computeYAxisValues();
// 畫白天折線圖
drawChart(canvas, mColorDay, mTempDay, mYAxisDay, 0);
// 畫夜間折線圖
drawChart(canvas, mColorNight, mTempNight, mYAxisNight, 1);
}
/**
* 計算y軸集合數值
*/
private void computeYAxisValues() {
// 存放白天最低溫度
int minTempDay = mTempDay[0];
// 存放白天最高溫度
int maxTempDay = mTempDay[0];
for (int item : mTempDay) {
if (item < minTempDay) {
minTempDay = item;
}
if (item > maxTempDay) {
maxTempDay = item;
}
}
// 存放夜間最低溫度
int minTempNight = mTempNight[0];
// 存放夜間最高溫度
int maxTempNight = mTempNight[0];
for (int item : mTempNight) {
if (item < minTempNight) {
minTempNight = item;
}
if (item > maxTempNight) {
maxTempNight = item;
}
}
// 白天,夜間中的最低溫度
int minTemp = minTempNight < minTempDay ? minTempNight : minTempDay;
// 白天,夜間中的最高溫度
int maxTemp = maxTempDay > maxTempNight ? maxTempDay : maxTempNight;
// 份數(白天,夜間綜合溫差)
float parts = maxTemp - minTemp;
// y軸一端到控件一端的距離
float length = mSpace + mTextSize + mTextSpace + mRadius;
// y軸高度
float yAxisHeight = mHeight - length * 2;
// 當溫度都相同時(被除數不能爲0)
if (parts == 0) {
for (int i = 0; i < LENGTH; i++) {
mYAxisDay[i] = yAxisHeight / 2 + length;
mYAxisNight[i] = yAxisHeight / 2 + length;
}
} else {
float partValue = yAxisHeight / parts;
for (int i = 0; i < LENGTH; i++) {
mYAxisDay[i] = mHeight - partValue * (mTempDay[i] - minTemp) - length;
mYAxisNight[i] = mHeight - partValue * (mTempNight[i] - minTemp) - length;
}
}
}
/**
* 畫折線圖
*
* @param canvas 畫布
* @param color 畫圖顏色
* @param temp 溫度集合
* @param yAxis y軸集合
* @param type 折線種類:0,白天;1,夜間
*/
private void drawChart(Canvas canvas, int color, int temp[], float[] yAxis, int type) {
color = Color.parseColor("#ffffff");
// 線畫筆
Paint linePaint = new Paint();
// 抗鋸齒
linePaint.setAntiAlias(true);
// 線寬
linePaint.setStrokeWidth(mStokeWidth);
linePaint.setColor(color);
// 空心
linePaint.setStyle(Paint.Style.STROKE);
// 點畫筆
Paint pointPaint = new Paint();
pointPaint.setAntiAlias(true);
pointPaint.setColor(color);
// 字體畫筆
Paint textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(mTextColor);
textPaint.setTextSize(mTextSize);
// 文字居中
textPaint.setTextAlign(Paint.Align.CENTER);
int alpha1 = 102;
int alpha2 = 255;
for (int i = 0; i < LENGTH; i++) {
// 畫線
if (i < LENGTH - 1) {
// 昨天
if (i == -1) {
linePaint.setAlpha(alpha1);
// 設置虛線效果
linePaint.setPathEffect(new DashPathEffect(new float[]{2 * mDensity, 2 * mDensity}, 0));
// 路徑
Path path = new Path();
// 路徑起點
path.moveTo(mXAxis[i], yAxis[i]);
// 路徑連接到
path.lineTo(mXAxis[i + 1], yAxis[i + 1]);
canvas.drawPath(path, linePaint);
} else {
if(type == 0) {
linePaint.setAlpha(76);
linePaint.setPathEffect(null);
linePaint.setStyle(Paint.Style.FILL);//設置實心
Path path = new Path(); //Path對象
path.moveTo(mXAxis[i], mYAxisDay[i]); //起始點
path.lineTo(mXAxis[i + 1], mYAxisDay[i + 1]); //連線到下一點
path.lineTo(mXAxis[i + 1], mYAxisNight[i + 1]); //連線到下一點
path.lineTo(mXAxis[i], mYAxisNight[i]); //連線到下一點
path.lineTo(mXAxis[i], mYAxisDay[i]); //連線到下一點
canvas.drawPath(path, linePaint); //繪製任意多邊形
}
//canvas.drawLine(mXAxis[i], yAxis[i], mXAxis[i + 1], yAxis[i + 1], linePaint);
}
}
// 畫點
if (i != 1) {
// 昨天
if (i == 0 || i == LENGTH - 1) {
/*pointPaint.setAlpha(alpha1);
canvas.drawCircle(mXAxis[i], yAxis[i], mRadius, pointPaint);*/
} else {
pointPaint.setAlpha(alpha2);
canvas.drawCircle(mXAxis[i], yAxis[i], mRadius, pointPaint);
}
// 今天
} else {
pointPaint.setAlpha(alpha2);
canvas.drawCircle(mXAxis[i], yAxis[i], mRadiusToday, pointPaint);
}
// 畫字
// 昨天
if (i == 0 || i == LENGTH - 1) {
/*textPaint.setAlpha(alpha1);
drawText(canvas, textPaint, i, temp, yAxis, type);*/
} else {
textPaint.setAlpha(alpha2);
drawText(canvas, textPaint, i, temp, yAxis, type);
}
}
}
/**
* 繪製文字
*
* @param canvas 畫布
* @param textPaint 畫筆
* @param i 索引
* @param temp 溫度集合
* @param yAxis y軸集合
* @param type 折線種類:0,白天;1,夜間
*/
private void drawText(Canvas canvas, Paint textPaint, int i, int[] temp, float[] yAxis, int type) {
switch (type) {
case 0:
// 顯示白天氣溫
canvas.drawText(temp[i] + "°", mXAxis[i], yAxis[i] - mRadius - mTextSpace, textPaint);
break;
case 1:
// 顯示夜間氣溫
canvas.drawText(temp[i] + "°", mXAxis[i], yAxis[i] + mTextSpace + mTextSize, textPaint);
break;
}
}
/**
* 設置高度,x軸集合
*/
private void setHeightAndXAxis() {
mHeight = getHeight();
// 控件寬
int width = getWidth();
int i = LENGTH - 2;
// 每一份寬
float w = width / (i*2);
for(int j =0;j<LENGTH;j++){
if(j == 0){
mXAxis[j] = 0;
} else if(j == LENGTH -1){
mXAxis[j] = width;
} else{
mXAxis[j] = w * (2*j -1);
}
}
/* mXAxis[0] = 0;
mXAxis[1] = w;
mXAxis[2] = w * 3;
mXAxis[3] = w * 5;
mXAxis[4] = w * 7;
mXAxis[5] = w * 9;
mXAxis[6] = width;*/
/* mXAxis[5] = w * 11;
mXAxis[6] = w * 13;*/
}
/**
* 設置白天溫度
*
* @param tempDay 溫度數組集合
*/
public void setTempDay(int[] tempDay) {
mTempDay = tempDay;
LENGTH = mTempDay.length;
mXAxis = new float[LENGTH];
mYAxisDay = new float[LENGTH];
mYAxisNight = new float[LENGTH];
/*mTempDay = new int[LENGTH];
mTempNight = new int[LENGTH];*/
}
/**
* 設置夜間溫度
*
* @param tempNight 溫度數組集合
*/
public void setTempNight(int[] tempNight) {
mTempNight = tempNight;
}
/**
* 設置白天曲線的顏色
*/
public void setColorDay(){}
}
佈局代碼:
<com.pingan.carowner.weather.view.WeatherChartView
android:id="@+id/line_char"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_below="@id/weather_over_view_item3"
android:layout_centerInParent="true"/>
代碼引用:
// 設置白天溫度曲線
mChartView = (WeatherChartView) findViewById(R.id.line_char);
mChartView.setTempDay(highTemp);//highTemp 高溫度集合
// 設置夜間溫度曲線
mChartView.setTempNight(lowTemp);//lowTemp 低溫集合
mChartView.invalidate();