仿天气预报界面

一、概述

最近看到一个要模仿华为手机天气预报的界面,于是自己试着写了一下,只做了一个简单的模仿,实现了显示设定的温度,并随着设定温度的不同,用不同颜色绘制温度区间,先看下大致思路:
- 绘制表示温度的圆弧
- 绘制显示温度文字
- 绘制刻度线
- 绘制刻度值
完成后的界面

二、绘制

1.画外侧圆弧

代码很简单,直接看代码:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint_circle.setColor(Color.WHITE);
        String text = String.valueOf(temperature) + "°";
        int width = getWidth();
        int height = getHeight();
        int radiu = (width - getPaddingLeft() - getPaddingRight()) / 2 - 100;
        canvas.translate(width / 2, height / 2);
        RectF rectF = new RectF(-radiu, -radiu, radiu, radiu);
        canvas.drawArc(rectF, 120, 300, false, paint_circle);
        mPaint.setTextSize(100);
        mPaint.getTextBounds(text, 0, text.length(), rect);
        canvas.drawText(text, -rect.width() / 2, rect.height() / 2, mPaint);

    }

前几句都是获取View的尺寸,具体的测量在onMeasure中设定,支持wrap-content和Padding,相信大家都写过这里不再粘贴代码,看看绘制圆弧的三行代码:

  • canvas.translate(width / 2, height / 2); 将画布的坐标移至屏幕的中央;
  • RectF rectF = new RectF(-radiu, -radiu, radiu, radiu); 设定圆弧的范围
  • canvas.drawArc(rectF, 120, 300, false, paint_circle); 传入起始角度和所话圆弧的角度,绘制圆弧;

    2. 绘制中间的文字

mPaint.setTextSize(100);
        mPaint.getTextBounds(text, 0, text.length(), rect);
        canvas.drawText(text, -rect.width() / 2, rect.height() / 2, mPaint);

和一般绘制文字一样,不过要注意此时画布的原点在屏幕的中间

3. 绘制刻度线
刻度线的绘制采用不断的旋转画布,当画布旋转至水平位置时画刻度线,关键在于弄清旋转的方向和旋转角度;

  private void drawItem(Canvas canvas, int radius) {
        mPaint.setTextSize(10);
        mPaint.setStrokeWidth(5);
        int weather = -20;
        canvas.save();
        int number = 300 / 5;
        canvas.rotate(-60);
        for (int i = 0; i <= number; i++) {
            if (weather <= temperature)
                paint_circle.setColor(getPaintColor(weather));
            else
                paint_circle.setColor(Color.WHITE);

            if (i == 0 || i == number) {
                paint_circle.setStrokeWidth(5);
                canvas.drawLine(-radius, 0, -radius + 40, 0, paint_circle);
            } else {
                paint_circle.setStrokeWidth(3);
                canvas.drawLine(-radius, 0, -radius + 30, 0, paint_circle);
            }
            weather++;
            canvas.rotate(5);
        }
        canvas.restore();
    }

看看代码,我设定温度区间在-20~40度,基本上天气都在这个范围之内,当然极端天气除外,从前面的代码可以看出,圆弧的旋转角度为300度
- number;计算每个刻度线之间的角度间隔
- canvas.rotate(-60); 将canvas逆时针旋转至水平位置,作为画刻度选的位置,每条刻度线都应先旋转到此位置,再画刻度线
- getPaintColor(weather) ; 根据温度度数选择对应颜色表示温度的指数,下载的代码中有,此处就不粘贴了,
- canvas.drawLine(-radius, 0, -radius + 40, 0, paint_circle); 绘制刻度线,可以看出每个刻度线都是绘制水平线,那为什么显示之后会是不同角度的线段呢,主要就是canvas的旋转起到的作用, canvas.save();和canvas.restore();之间进行旋转绘制,之后画布在恢复原状。

4. 绘制刻度值
这一部分就是根据温度区间和圆弧的度数确定,每一个温度值对应的位置,并写上相应的数字,具体利用度数的正弦函数确定其实坐标,别忘了将度数转化为弧度制:

private void drawText(Canvas canvas, int radius) {
        int textDegree = 120;
        int weather = -20;

        for (int i = 0; i <= 12; i++) {
            String string = String.valueOf(weather) + "°";
            mPaint.setTextSize(40);
            mPaint.getTextBounds(string, 0, string.length(), rect1);
            float x = (float) getX(radius + 20, textDegree * Math.PI / 180);
            float y = (float) getY(radius + 20, textDegree * Math.PI / 180);
            canvas.drawText(string, x, y - rect1.height() / 2, mPaint);
            weather += 5;
            textDegree += 25;
        }
    }

上述方法中主要的就是getX()和getY()方法,下面看看这两个方法:

 private double getX(int radius, double degree) {
        return getTextX(radius, degree);
    }

    private double getY(int radius, double degree) {
        return getTextY(radius, degree);
    }

    private double getTextX(int radius, double degree) {
        double x = 0;
        double d = Math.PI;
        x = radius * Math.cos(degree);
        if (degree > d / 2 && degree < 3 * d / 2)
            x = x - rect1.width();
        return x;
    }

    private double getTextY(int radius, double degree) {
        double y = radius * Math.sin(degree);
        double d = Math.PI;
        if (degree < d || degree > 2d)
            y += rect1.height();
        return y;
    }

由于很久没用这个正弦函数,都忘记把度数转换为弧度了,之后发现每个坐标都不对,后来又看了一下那两条妖娆的正弦和余弦曲线,getTextX()和getTextY()主要是讲获取到的位置,根据实际情况调整一下,相信大家也会想到,我们获取的坐标只是对应圆弧的坐标,并不能直接在此处写上文字,因为当X坐标为负时,如果文字的位置不便宜,字就要写到圆弧里了,到此View就绘制完成了。

三、代码调用

因为View里面设置了setTemperature()的方法,此处可以使用属性动画让温度值不断增加,从而自动绘制:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_weather_view_);
        westherView = (WestherView) findViewById(R.id.weather);
        ObjectAnimator.ofFloat(westherView,"temperature",0,30).setDuration(2000).start();

    }

代码下载:
https://github.com/AlexTiti/TemperatureView

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值