Android 天气APP(六)旋转风车显示风力、风向

2022-05-10 10:56:57 浏览数 (2)

8. 旋转风车

这个时候就要用到自定义View了,这个工具类的代码也并不是我自己写的,而是网络上找的,

① 样式

在模块的res文件夹下的values文件下新建一个styles.xml

里面的代码如下:

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--白色风车-->
    <declare-styleable name="WhiteWindmills">
        <attr name="windColor" format="reference|color" />
    </declare-styleable>
</resources>

② 自定义View

然后就是自定义VIew了,

在模块的com.llw.mvplibrary下面创建一个view的包,包下创建一个名为WhiteWindmills的类。 代码如下:

代码语言:javascript复制
package com.llw.mvplibrary.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import com.llw.mvplibrary.R;

import java.lang.ref.WeakReference;

/**
 * 白色风车
 */
public class WhiteWindmills extends View {

    /**
     * 叶片的长度
     */
    private float mBladeRadius;
    /**
     * 风车叶片旋转中心x
     */
    private int mCenterY;
    /**
     * 风车叶片旋转中心y
     */
    private int mCenterX;
    /**
     * 风车旋转中心点圆的半径
     */
    private float mPivotRadius;
    private Paint mPaint = new Paint();
    /**
     * 风车旋转时叶片偏移的角度
     */
    private int mOffsetAngle;
    private Path mPath = new Path();
    /**
     * 风车支柱顶部和底部为了画椭圆的矩形
     */
    private RectF mRect = new RectF();
    /**
     * 控件的宽
     */
    private int mWid;
    /**
     * 控件高
     */
    private int mHei;
    /**
     * 控件颜色
     */
    private int mColor;
    private MsgHandler mHandler = new MsgHandler(this);

    public WhiteWindmills(Context context) {
        this(context, null);
    }

    public WhiteWindmills(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WhiteWindmills(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.WhiteWindmills);
        if (array != null) {
            mColor = array.getColor(R.styleable.WhiteWindmills_windColor, Color.WHITE);

            array.recycle();
        }
        //抗锯齿
        mPaint.setAntiAlias(true);
        mPaint.setColor(mColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int heiMeasure = MeasureSpec.getSize(heightMeasureSpec);
        int heiMode = MeasureSpec.getMode(heightMeasureSpec);
        int widMode = MeasureSpec.getMode(widthMeasureSpec);
        int widMeasure = MeasureSpec.getSize(widthMeasureSpec);

        mWid = widMeasure;
        mHei = heiMeasure;
        mCenterY = mWid / 2;
        mCenterX = mWid / 2;

        mPivotRadius = (float) mWid / (float) 40;
        mBladeRadius = mCenterY - 2 * mPivotRadius;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //画扇叶旋转的中心
        drawPivot(canvas);

        //画扇叶
        drawWindBlade(canvas);

        //画底部支柱
        drawPillar(canvas);
    }

    /**
     * 画风车支点
     *
     * @param canvas
     */
    private void drawPivot(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(mCenterX, mCenterY, mPivotRadius, mPaint);
    }

    /**
     * 画叶片
     *
     * @param canvas
     */
    private void drawWindBlade(Canvas canvas) {
        canvas.save();
        mPath.reset();
        //根据偏移量画初始时画布的位置
        canvas.rotate(mOffsetAngle, mCenterX, mCenterY);
        //画三角形扇叶
        mPath.moveTo(mCenterX, mCenterY - mPivotRadius);// 此点为多边形的起点
        mPath.lineTo(mCenterX, mCenterY - mPivotRadius - mBladeRadius);
        mPath.lineTo(mCenterX   mPivotRadius, mPivotRadius   mBladeRadius * (float) 2 / (float) 3);
        mPath.close(); // 使这些点构成封闭的多边形
        canvas.drawPath(mPath, mPaint);

        //旋转画布120度,画第二个扇叶
        canvas.rotate(120, mCenterX, mCenterY);
        canvas.drawPath(mPath, mPaint);

        //旋转画布120度,画第三个扇叶
        canvas.rotate(120, mCenterX, mCenterY);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
    }

    /**
     * 画支柱
     *
     * @param canvas
     */
    private void drawPillar(Canvas canvas) {
        mPath.reset();
        //画上下半圆之间的柱形
        mPath.moveTo(mCenterX - mPivotRadius / 2, mCenterY   mPivotRadius   mPivotRadius / 2);
        mPath.lineTo(mCenterX   mPivotRadius / 2, mCenterY   mPivotRadius   mPivotRadius / 2);
        mPath.lineTo(mCenterX   mPivotRadius, mHei - 2 * mPivotRadius);
        mPath.lineTo(mCenterX - mPivotRadius, mHei - 2 * mPivotRadius);
        mPath.close();

        //画顶部半圆
        mRect.set(mCenterX - mPivotRadius / 2, mCenterY   mPivotRadius, mCenterX   mPivotRadius / 2, mCenterY   2 * mPivotRadius);
        mPath.addArc(mRect, 180, 180);
        //画底部半圆
        mRect.set(mCenterX - mPivotRadius, mHei - 3 * mPivotRadius, mCenterX   mPivotRadius, mHei - mPivotRadius);
        mPath.addArc(mRect, 0, 180);

        canvas.drawPath(mPath, mPaint);
    }

    /**
     * 开始旋转
     */
    public void startRotate() {
        stop();
        mHandler.sendEmptyMessageDelayed(0, 10);
    }

    /**
     * 停止旋转
     */
    public void stop() {
        mHandler.removeMessages(0);
    }

    static class MsgHandler extends Handler {
        private WeakReference<WhiteWindmills> mView;

        MsgHandler(WhiteWindmills view) {
            mView = new WeakReference<WhiteWindmills>(view);
        }

        @Override
        public void handleMessage(Message msg) {
            WhiteWindmills view = mView.get();
            if (view != null) {
                view.handleMessage(msg);
            }
        }
    }

    private void handleMessage(Message msg) {
        if (mOffsetAngle >= 0 && mOffsetAngle < 360) {
            mOffsetAngle = mOffsetAngle   1;
        } else {
            mOffsetAngle = 1;
        }
        invalidate();
        startRotate();
    }
}

这个部分完成之后,修改布局,将这一块加进去。

③ 使用与运行显示

这部分代码如下:

代码语言:javascript复制
					<!--风力展示-->
                    <LinearLayout
                        android:orientation="horizontal"
                        android:padding="20dp"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">
                        <RelativeLayout
                            android:id="@ id/rl_wind"
                            android:layout_width="130dp"
                            android:layout_height="120dp">
                            <!--大风车-->
                            <com.llw.mvplibrary.view.WhiteWindmills
                                android:id="@ id/ww_big"
                                android:layout_width="100dp"
                                android:layout_height="120dp" />
                            <!--小风车-->
                            <com.llw.mvplibrary.view.WhiteWindmills
                                android:id="@ id/ww_small"
                                android:layout_width="50dp"
                                android:layout_height="60dp"
                                android:layout_alignParentBottom="true"
                                android:layout_alignParentRight="true"
                                />
                        </RelativeLayout>

                        <LinearLayout
                            android:gravity="center"
                            android:orientation="vertical"
                            android:layout_weight="1"
                            android:layout_width="0dp"
                            android:layout_height="match_parent">
                            <!--风向-->
                            <TextView
                                android:id="@ id/tv_wind_direction"
                                android:textColor="#FFF"
                                android:textSize="@dimen/sp_14"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"/>
                            <!--风力-->
                            <TextView
                                android:layout_marginTop="20dp"
                                android:id="@ id/tv_wind_power"
                                android:textColor="#FFF"
                                android:textSize="@dimen/sp_14"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"/>
                        </LinearLayout>
                    </LinearLayout>

代码中:

风力的数据其实在天气数据的返回值就有了,就是第一个接口,接下来修改代码

代码如下:

代码语言:javascript复制
			tvWindDirection.setText("风向     "   response.body().getHeWeather6().get(0).getNow().getWind_dir());//风向
            tvWindPower.setText("风力     "   response.body().getHeWeather6().get(0).getNow().getWind_sc()   "级");//风力
            wwBig.startRotate();//大风车开始转动
            wwSmall.startRotate();//小风车开始转动

记得在页面销毁的时候停止这个风车:

代码语言:javascript复制
	/**
     * 页面销毁时
     */
    @Override
    public void onDestroy() {
        wwBig.stop();//停止大风车
        wwSmall.stop();//停止小风车
        super.onDestroy();
    }

运行一下:

0 人点赞