##仿华为天气动画

效果图:

这里写图片描述

图中效果分为3个部分:污染轨迹动画,太阳轨迹动画,太阳闪烁动画,下面分析如何实现太阳轨迹动画和太阳闪烁动画.

思路:

1.画出太阳轨迹背景
2.使用动画描绘太阳运动轨迹
3.根据太阳运动轨迹运动的角度得到太阳圆心的坐标并画出太阳(三角函数)
4.画出太阳闪烁的动画(三角函数,这里注释里详细注释)

关键代码:

public class WeatherView extends View {

    /**
     * 污染进度
     */
    private int progressPolluton;

    /**
     * 太阳轨迹进度
     */
    private int progressSunPath;

    /**
     * 太阳每条光线闪烁进度
     */
    private int progressSun;

    /**
     * 太阳光线条数
     */
    private int sunshineCount = 10;

    /**
     * 每个模块的上下间距
     */
    private float marginVertical = ScreenUtils.dp2Px(20);

    /**
     * 污染指数圆半径
     */
    private float radiusPollution = dp2Px(70);

    /**
     * 太阳半径
     */
    private float radiusSun = dp2Px(10);

    /**
     * 太阳轨迹半径
     */
    private float radiusSunPath = dp2Px(140);

    /**
     * 画笔
     */
    private Paint paint = new Paint();

    private RectF rectF = new RectF();


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

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

    public WeatherView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        pollutionAnimation();
        sunPathAnimation();
        sunShineAnimation();
    }

    private void pollutionAnimation() {//污染指数
        ValueAnimator animator1 = ValueAnimator.ofInt(400).setDuration(2000);
        animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                progressPolluton = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator1.start();
    }

    private void sunPathAnimation() {//太阳轨迹
        ValueAnimator animator2 = ValueAnimator.ofInt(0, 180).setDuration(3000);
        animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                progressSunPath = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator2.start();
    }

    private void sunShineAnimation() {//太阳
        ValueAnimator animator3 = ValueAnimator.ofInt(0, 24).setDuration(2000);
        animator3.setInterpolator(new LinearInterpolator());
        animator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                progressSun = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator3.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                sunShineAnimation();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animator3.start();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        int widthCenter = getWidth() / 2;
        drawPullotionIndex(canvas, widthCenter);
        drawSunPath(canvas, widthCenter);
        drawSun(canvas, widthCenter);
    }

    private void drawPullotionIndex(Canvas canvas, int widthCenter) {
        paint.reset();
        paint.setAntiAlias(true);
        paint.setColor(Color.parseColor("#888888"));
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(ScreenUtils.dp2Px(5));
        paint.setStrokeCap(Paint.Cap.ROUND);
        rectF.set(widthCenter - radiusPollution, marginVertical, widthCenter + radiusPollution, marginVertical + radiusPollution * 2);
        canvas.drawArc(rectF, 150, 240, false, paint);//画出污染指数背景

        paint.reset();
        paint.setAntiAlias(true);
        paint.setColor(Color.parseColor("#E91E63"));
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(ScreenUtils.dp2Px(5));
        paint.setStrokeCap(Paint.Cap.ROUND);
        if (progressPolluton != 0) {
            canvas.drawArc(rectF, 150, progressPolluton * (240f / 500), false, paint);
        }

        paint.reset();
        paint.setAntiAlias(true);
        paint.setTextSize(ScreenUtils.sp2Px(12));
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText("重度污染", widthCenter, marginVertical + radiusPollution, paint);

        paint.setTextSize(ScreenUtils.sp2Px(14));
        canvas.drawText(String.valueOf(progressPolluton), widthCenter, marginVertical + radiusPollution + paint.getFontSpacing(), paint);

        int leftPollutionX = (int) (widthCenter + radiusPollution * Math.cos(150 * Math.PI / 180));//污染起始值横坐标
        int leftPollutionY = (int) (marginVertical + radiusPollution + radiusPollution * Math.sin(150 * Math.PI / 180));//污染起始值纵坐标
        canvas.drawText("0", leftPollutionX, leftPollutionY + ScreenUtils.dp2Px(16), paint);

        int rightPollutionX = (int) (widthCenter + radiusPollution * Math.cos(30 * Math.PI / 180));//污染最大值横坐标
        int rightPollutionY = (int) (marginVertical + radiusPollution + radiusPollution * Math.sin(30 * Math.PI / 180));//污染最大值纵坐标
        canvas.drawText("500", rightPollutionX, rightPollutionY + ScreenUtils.dp2Px(16), paint);
    }

    private void drawSunPath(Canvas canvas, int widthCenter) {
        PathEffect pathEffect = new DashPathEffect(new float[]{10, 10}, 10);
        paint.reset();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.parseColor("#888888"));
        paint.setPathEffect(pathEffect);
        rectF.set(widthCenter - radiusSunPath, marginVertical + 2 * radiusPollution + 100, widthCenter + radiusSunPath, marginVertical + 2 * radiusPollution + 100 + 2 * radiusSunPath);
        canvas.drawArc(rectF, 180, 180, false, paint);

        paint.reset();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.parseColor("#E91E63"));
        paint.setPathEffect(pathEffect);
        canvas.drawArc(rectF, 180, progressSunPath, false, paint);

        paint.reset();
        paint.setAntiAlias(true);
        canvas.drawLine(0, marginVertical + 2 * radiusPollution + 100 + radiusSunPath, getWidth(), marginVertical + 2 * radiusPollution + 100 + radiusSunPath, paint);

        paint.setTextSize(ScreenUtils.dp2Px(14));
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText("5:30", widthCenter - radiusSunPath, marginVertical + 2 * radiusPollution + 100 + radiusSunPath + ScreenUtils.dp2Px(16), paint);
        canvas.drawText("18:30", widthCenter + radiusSunPath, marginVertical + 2 * radiusPollution + 100 + radiusSunPath + ScreenUtils.dp2Px(16), paint);
    }

    private void drawSun(Canvas canvas, int widthCenter) {
        paint.reset();
        paint.setAntiAlias(true);
        paint.setColor(Color.parseColor("#FFA82C"));

        float cX = (float) (widthCenter + radiusSunPath * Math.cos((progressSunPath + 180) * Math.PI / 180));
        float cY = (float) (marginVertical + 2 * radiusPollution + 100 + radiusSunPath + radiusSunPath * Math.sin((progressSunPath + 180) * Math.PI / 180));
        canvas.drawCircle(cX, cY, radiusSun, paint);
        int perAngle = 360 / sunshineCount;
        paint.setStrokeWidth(4);
        //绘制太阳光线需要知道线的起始和结束坐标,通过太阳轨迹运动轨迹可以得到太阳的圆心坐标,再以该圆心坐标
        //找到两个不同半径的圆(当然,并不用画出这两个圆,我们只是需要它们上面的点用来画光线)
        for (int i = 0; i < sunshineCount; i++) {//画太阳光芒
            int angle = perAngle * i;
            int inX = (int) (cX + (radiusSun + 5) * Math.cos(angle * Math.PI / 180));//光线起始x坐标
            int inY = (int) (cY + (radiusSun + 5) * Math.sin(angle * Math.PI / 180));//光线起始y坐标
            int outX = (int) (cX + (radiusSun + progressSun) * Math.cos(angle * Math.PI / 180));//光线结束x坐标
            int outY = (int) (cY + (radiusSun + progressSun) * Math.sin(angle * Math.PI / 180));//光线结束y坐标
            canvas.drawLine(inX, inY, outX, outY, paint);
        }
    }

    public void startAnimation() {
        pollutionAnimation();
        sunPathAnimation();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值