Android 天氣APP(六)旋轉風車顯示風力、風向

上一篇:Android 天氣APP(五)天氣預報、生活指數的數據請求與渲染

8. 旋轉風車

這個時候就要用到自定義View了,這個工具類的代碼也並不是我自己寫的,而是網絡上找的,

① 樣式

在模塊的res文件夾下的values文件下新建一個styles.xml
在這裏插入圖片描述
裏面的代碼如下:

<?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的類。
代碼如下:

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();
    }
}

這個部分完成之後,修改佈局,將這一塊加進去。

③ 使用與運行顯示

在這裏插入圖片描述
這部分代碼如下:

					<!--風力展示-->
                    <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>

代碼中:
在這裏插入圖片描述
風力的數據其實在天氣數據的返回值就有了,就是第一個接口,接下來修改代碼
在這裏插入圖片描述
代碼如下:

			tvWindDirection.setText("風向     " + response.body().getHeWeather6().get(0).getNow().getWind_dir());//風向
            tvWindPower.setText("風力     " + response.body().getHeWeather6().get(0).getNow().getWind_sc() + "級");//風力
            wwBig.startRotate();//大風車開始轉動
            wwSmall.startRotate();//小風車開始轉動

記得在頁面銷燬的時候停止這個風車:

	/**
     * 頁面銷燬時
     */
    @Override
    public void onDestroy() {
        wwBig.stop();//停止大風車
        wwSmall.stop();//停止小風車
        super.onDestroy();
    }

運行一下:

在這裏插入圖片描述

下一篇:Android 天氣APP(七)城市切換 之 城市數據源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章