华为天气-自定义控件-风车

一个高仿华为天气的自定义风车View

import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * Created by jayyu on 2018/2/19.
 */

public class WindTurbine extends View {

    private float mBaseDegrees = 0;
    private int mBladeColor = Color.WHITE;

    private ObjectAnimator animator;
    private int mDuration = 5000;
    private boolean isAnimationRunning = false;
    private boolean stopAnimation = false;


    public WindTurbine(Context context) {
        super(context);
    }

    public WindTurbine(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        RectF windTurbineMainBorder = new RectF(0, 0, getMeasuredHeight() / 3 * 2, getMeasuredHeight());
        drawWindTurbine(canvas, windTurbineMainBorder);
        windTurbineMainBorder = new RectF(getMeasuredHeight() / 3 * 2, getMeasuredHeight() / 2, getMeasuredHeight(), getMeasuredHeight());
        drawWindTurbine(canvas, windTurbineMainBorder);
    }

    private void drawWindTurbine(Canvas canvas, RectF border) {

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(5);
        // 开启硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, paint);

        //绘制柄
        Pylon pylon = new Pylon(border.left + border.width() / 2, border.top + border.height() / 3 + border.height() / 3 / 10, border.height() / 3 * 2 - border.height() / 3 / 10);
        Path pylonPath = pylon.getPath();
        paint.setColor(mBladeColor);
        canvas.drawPath(pylonPath, paint);

        paint.setColor(mBladeColor);
        Blade blade = new Blade(border.left + border.width() / 2, border.top + border.height() / 3, border.height() / 3, mBaseDegrees);
        Path path = blade.getBladePath();

        // 开始绘制风页
        canvas.drawPath(path, paint);
        canvas.drawPath(blade.getRotateBladePath(120), paint);
        canvas.drawPath(blade.getRotateBladePath(240), paint);
        canvas.drawCircle(border.left + border.width() / 2, border.top + border.height() / 3, border.height() / 3 / 15, paint);
    }

    //基塔类
    private class Pylon {
        // 基塔坐标(从上往下绘制叶片)
        private float mPetioleX;
        private float mPetioleY;
        // 总共的长度
        private float mLength;

        private Path mPath;

        public Pylon(float mPetioleX, float mPetioleY, float mLength) {
            this.mPetioleX = mPetioleX;
            this.mPetioleY = mPetioleY;
            this.mLength = mLength;
            mPath = new Path();
            // 最顶部的横杠左端开始往下绘制
            float radio = mLength / 20;
            mPath.moveTo(mPetioleX, mPetioleY);
            mPath.lineTo(mPetioleX - radio / 4, mPetioleY);
            mPath.lineTo(mPetioleX - radio / 1.742f, mPetioleY + mLength - radio / 2);
            mPath.quadTo(mPetioleX, mPetioleY + mLength, mPetioleX + radio / 1.742f, mPetioleY + mLength - radio / 2);
            mPath.lineTo(mPetioleX + radio / 1.742f, mPetioleY + mLength - radio / 2);
            mPath.lineTo(mPetioleX + radio / 4, mPetioleY);
            mPath.lineTo(mPetioleX, mPetioleY);

            mPath.setFillType(Path.FillType.WINDING);
        }

        public Path getPath() {
            return mPath;
        }
    }

    //叶片类
    private class Blade {
        // 叶柄坐标(从下往上绘制叶片)
        private float mPetioleX;
        private float mPetioleY;
        // 总共的长度
        private float mLength;
        private float mDiv;
        //度数
        private float mDegrees;
        private Path mPath;

        public Blade(float petioleX, float petioleY, float length, float mDegrees) {
            this.mPetioleX = petioleX;
            this.mPetioleY = petioleY;
            this.mLength = length;
            this.mDiv = (float) (length / 10.0);
            mPath = new Path();
            mPath.moveTo(mPetioleX, mPetioleY - mDiv);
            mPath.quadTo(mPetioleX - mDiv / 5 * 3, mPetioleY - mDiv * 9 / 2, mPetioleX, mPetioleY - mLength);
            mPath.quadTo(mPetioleX + mDiv, mPetioleY - mDiv * 9 / 2, mPetioleX, mPetioleY - mDiv);
            Matrix matrix = new Matrix();
            matrix.preRotate(mDegrees, mPetioleX, mPetioleY);
            mPath.transform(matrix);
        }

        public Path getBladePath() {
            return mPath;
        }

        public Path getRotateBladePath(float rotateDegrees) {
            Path path = new Path();
            Matrix matrix = new Matrix();
            matrix.preRotate(rotateDegrees, mPetioleX, mPetioleY);
            mPath.transform(matrix, path);
            return path;
        }
    }

    public void setMBaseDegrees(float mBaseDegrees) {
        this.mBaseDegrees = mBaseDegrees;
        invalidate();
    }

    public void startRotateAnimation() {
        Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
        Keyframe keyframe2 = Keyframe.ofFloat(1, 359);
        PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("mBaseDegrees", keyframe1, keyframe2);
        animator = ObjectAnimator.ofPropertyValuesHolder(this, holder);
        animator.setDuration(mDuration);
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(ObjectAnimator.INFINITE);
        animator.start();
        stopAnimation = false;
        isAnimationRunning = true;
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float degrees = (Float) animation.getAnimatedValue();
                if (((degrees >= 0f && degrees <= 4) || (degrees >= 120f && degrees <= 124f) || (degrees >= 240 && degrees <= 244)) && stopAnimation) {
                    mBaseDegrees = 0;
                    invalidate();
                    animator.cancel();
                    isAnimationRunning = false;
                }
            }
        });
    }

    public void stopRotateAnimation() {
        stopAnimation = true;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    public int getDuration() {
        return mDuration;
    }

    public void setDuration(int mDuration) {
        this.mDuration = mDuration;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        animator.cancel();
    }
}

你可能感兴趣的:(华为天气-自定义控件-风车)