先看一下效果,完整代码:
首先我们定义几个变量用来存放数据
private static final int DAY_NUM = 6; //天数,实际应用可以根据数据调整
private int[] temMax = new int[DAY_NUM];//最高温度的集合
private int[] temMin = new int[DAY_NUM];//最低温度的集合
private Bitmap[] weatherIcon = new Bitmap[DAY_NUM];//天气图片集合
private String[] time = new String[DAY_NUM];//时间集合
我们这个图标主要分5部分:每天之间的分割线,最高温度曲线,最低温度曲线,天气图标,日期。只要一步一步实现即可
1 分割线
这个很简单,平分之后划线即可,注意每条线坐标的计算
private void drawDayDivide(Canvas canvas,int flag) {
for(int i = 1 ; i < flag ; i++){
canvas.drawLine(i * dayWidth, DIVIDE_MARGIN, i * dayWidth, mHeight - DIVIDE_MARGIN, mDayDividePaint);
}
}
2. 最高最低温度曲线
我们将整个图标的高度分为三部分,最高温度曲线和最低温度曲线分别占用前两块区域。划线的第一步是描点,先得到一组温度中的最大最小值,确定线的高低点,然后中间的数据依比例画出对应点,最后连线:
数据的计算:
maxInMax = getMax(temMax);
minInMax = getMin(temMax);
maxInMin = getMax(temMin);
minInMin = getMin(temMin);
diffInMax = maxInMax - minInMax;
diffInMin = maxInMin - minInMin;
diffInMaxHeight = diffInMax == 0 ? 0: (partHeight- PART_MARGIN *2) / diffInMax;
diffInMinHeight = diffInMin == 0 ? 0: (partHeight- PART_MARGIN *2) / diffInMin;
private int getMin(int[] m) {
int tmp = m[0];
for (int i : m) {
tmp = tmp < i ? tmp : i;
}
return tmp;
}
private int getMax(int[] m) {
int tmp = m[0];
for (int i : m) {
tmp = tmp > i ? tmp : i;
}
return tmp;
}
绘图:
private void drawPointAndTemperatureLine(Canvas canvas,int flag) {
int x,y;
Path maxPath = new Path();
Path minPath = new Path();
String temp ;
//循环画出所有点
for(int i = 0 ; i < flag ; i++){
//第一个点的横坐标
x = firstPointX + dayWidth * i;
//计算纵坐标,如果所有数据都一样,则画到对应区域中央,否则根据比例定点
if(diffInMax == 0){
y = partHeight / 2;
}else{
y = Math.abs(temMax[i] - maxInMax) * diffInMaxHeight + PART_MARGIN;
}
//画点
canvas.drawCircle(x , y , POINT_RADIUS , mPointPaint);
temp = temMax[i]+DEGREE;
//画出温度文字,要在点的上方居中
canvas.drawText(temp , x - mTextPaint.measureText(temp)/2 , y - TEXT_MARGIN , mTextPaint);
//对path操作
if(i == 0){
maxPath.moveTo(x , y);
}else{
maxPath.lineTo(x , y);
}
//绘制最低温度的点,逻辑和上面一样
if(diffInMin == 0){
y = partHeight / 2 + partHeight;
}else{
y = Math.abs(temMin[i] - maxInMin) * diffInMinHeight + PART_MARGIN + partHeight;
}
canvas.drawCircle(x , y , POINT_RADIUS , mPointPaint);
temp = temMin[i]+DEGREE;
canvas.drawText(temp , x - mTextPaint.measureText(temp)/2 , y - TEXT_MARGIN , mTextPaint);
if(i == 0){
minPath.moveTo(x , y);
}else{
minPath.lineTo(x , y);
}
}
//连线
canvas.drawPath(maxPath , mMaxLinePaint);
canvas.drawPath(minPath , mMinLintPaint);
}
3.天气图片及文字
我们之前将整个高度划分为三部分,图片及文字占最后一部分:
private void drawWeatherIconAndText(Canvas canvas,int flag) {
Bitmap icon = null;
for (int i = 0 ; i < flag ; i++){
if(weatherIcon[i]==null){
continue;
}
float r = (partHeight - partHeight * 3 / 9 - mTextPaint.descent() + mTextPaint.ascent() ) / weatherIcon[i].getHeight();
icon = scaleBitmap(weatherIcon[i],r);
canvas.drawBitmap(icon, dayWidth / 2 - icon.getWidth() / 2 + dayWidth * i, partHeight * 2 , null);
canvas.drawText(time[i], dayWidth / 2 - mTextPaint.measureText(time[i]) / 2 + dayWidth * i, partHeight * 2 + icon.getHeight() + partHeight * 2 / 9, mTextPaint);
}
}
private Bitmap scaleBitmap(Bitmap origin, float ratio) {
if (origin == null) {
return null;
}
int width = origin.getWidth();
int height = origin.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(ratio, ratio);
Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
if (newBM.equals(origin)) {
return newBM;
}
return newBM;
}
首先要对图片进行一次缩放,由于图片要主要显示,所以去掉上下边距及文字的高度,剩下的都给图片来显示。文字的绘制也没什么难点,主要是居中即可。
4. 动画
我们这里简单实现一个从左到右依次出现的动画。这里转换一下逻辑,正常绘制时每块需要循环DAY_NUM 次,开启动画时我们将要绘制的天数递增,每增加一次,就绘制一次,这样就有动画效果了:
public void startAnimation(){
animFlag = 0;
handler.sendEmptyMessage(0);
}
public void cleanAnimation(){
handler.removeMessages(0);
animFlag = 0;
postInvalidate();
}
private android.os.Handler handler = new android.os.Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (animFlag < DAY_NUM){
postInvalidate();
animFlag++;
sendEmptyMessageDelayed(0,50);
}
}
};
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(getResources().getColor(R.color.colorTransparent));
computer();
drawDayDivide(canvas,animFlag);
drawPointAndTemperatureLine(canvas,animFlag);
drawWeatherIconAndText(canvas,animFlag);
}
网友评论