一个高仿华为天气的自定义风车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();
}
}