一个简单的天气图表

2018-05-08  本文已影响0人  留给时光吧

先看一下效果,完整代码


首先我们定义几个变量用来存放数据

    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);
    }
上一篇 下一篇

猜你喜欢

热点阅读