飞行的星星

这个主要想分享一下,类似彩带快速飞行的动效,主要可以作用于飞入购物车动效。飞机飞行尾气跟随动效等。主要灵感来自于很多小游戏里的点击飞行特效。先看看效果:

先看看尾部不停的闪耀和不停地产生新的star开始,原理就是给定一个角度,然后随机生成偏移量。在给定角度内,不停的使用Paint画出bitmap,然后不停的随机计算位置,然后再给上透明度的变化就可以了。

 private void init() {
        // 0~360
        float direction;
        if (mAngle >= 0 && mAngle < 90) {
            // 270~360
            direction = 270 + mAngle;
        } else if (mAngle >= 90 && mAngle < 180) {
            // 0~90
            direction = mAngle - 90;
        } else if (mAngle >= 180 && mAngle < 270) {
            // 90~180
            direction = mAngle - 90;
        } else {
            // 180~270
            direction = mAngle - 90;
        }

        Random random = new Random();
        for (int i = 0; i < mCount; i++) {
            // 偏移角度在 -15~15
            float t = random.nextInt(30) - 15;
            t = direction + t;
            if (t > 360) {
                t = t - 360;
            }
            if (t < 0) {
                t = t + 360;
            }
            t = (float) Math.toRadians(t);
            elements.add(new Element(t, mLaunchSpeed * random.nextFloat()));
        }

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.WHITE);

        mAnimator = ValueAnimator.ofFloat(1, 0);
        mAnimator.setDuration(DEFAULT_DURATION);
        mAnimator.setInterpolator(new AccelerateInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                mAnimatedValue = (float) animator.getAnimatedValue();
                // 计算位置
                for (Element element : elements) {
                    element.x += (float) (Math.cos(element.direction) * element.speed) * mAnimatedValue;
                    element.y += (float) (Math.sin(element.direction) * element.speed) * mAnimatedValue;
                }
            }
        });
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mListener != null)
                    mListener.onAnimatorEnd();
            }
        });
    }

这么直接将bitmap画上去的就会存在一个问题,就是就是图片显示大小不可控。因此需要将bitmap大小改变下。

 public void draw(Canvas canvas) {
        mPaint.setAlpha((int) (255 * mAnimatedValue));
        Bitmap bitmap = BitmapFactory.decodeResource(BaseApplication.getContext().getResources(), R.mipmap.icon_fly_star);
        Random random = new Random();
        int radomSize = bitmap.getWidth() / 10 + random.nextInt(bitmap.getWidth() / 2);
        bitmap = imageScale(bitmap, radomSize, radomSize);
        for (Element element : elements) {
            //画圆点性能更高
//            canvas.drawCircle(mLocationX + element.x, mLocationY + element.y, mElementSize, mPaint);
            canvas.drawBitmap(bitmap, mLocationX + element.x, mLocationY + element.y, mPaint);
        }
    }

    /*
    设置bitmap尺寸
     */
    public Bitmap imageScale(Bitmap bitmap, int dst_w, int dst_h) {
        int src_w = bitmap.getWidth();
        int src_h = bitmap.getHeight();
        float scale_w = ((float) dst_w) / src_w;
        float scale_h = ((float) dst_h) / src_h;
        Matrix matrix = new Matrix();
        matrix.postScale(scale_w, scale_h);
        Bitmap dstbmp = Bitmap.createBitmap(bitmap, 0, 0, src_w, src_h, matrix,
                true);
//        Random random = new Random();
//        return getAlplaBitmap(dstbmp, 20+random.nextInt(80));

        return dstbmp;
    }

这样就出现了星星不停的闪烁,不停的出现新的星星,剩下的就是移动了,获取两个点的坐标,然后再获取角度,将闪烁的星星进行角度旋转,然后讲这个星星进行移动。从起始点移动到目标点就可以了。

  private void moveStartLocation() {
        view_anim.setVisibility(View.INVISIBLE);
        int[] startlocation = new int[2];
        tv_start.getLocationOnScreen(startlocation);
        final int startx = startlocation[0];
        final int starty = startlocation[1];
        int[] targetlocation = new int[2];
        tv_target.getLocationOnScreen(targetlocation);
        final int targetx = targetlocation[0];
        final int targety = targetlocation[1];
        rotationBetweenLines = getRotationBetweenLines(targetx, targety, startx, starty);

        final int viewSize = dp2px(this, 150);

        ObjectAnimator translationX = new ObjectAnimator().ofFloat(view_anim, "translationX", 0, startx + viewSize);
        ObjectAnimator translationY = new ObjectAnimator().ofFloat(view_anim, "translationY", 0, starty + viewSize);
        AnimatorSet animatorSet = new AnimatorSet();  //组合动画
        animatorSet.playTogether(translationX, translationY); //设置动画
        animatorSet.setDuration(10);  //设置动画时间
        animatorSet.start(); //启动
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                view_anim.setVisibility(View.VISIBLE);
                showFlyAnim(startx - viewSize, starty - viewSize, targetx - viewSize, targety - viewSize);

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }


    private void showFlyAnim(int startx, int starty, int targetx, int targety) {

        ObjectAnimator translationX = new ObjectAnimator().ofFloat(view_anim, "translationX", startx, targetx);
        ObjectAnimator translationY = new ObjectAnimator().ofFloat(view_anim, "translationY", starty, targety);
        AnimatorSet animatorSet = new AnimatorSet();  //组合动画
        animatorSet.playTogether(translationX, translationY); //设置动画
        animatorSet.setDuration(1000);  //设置动画时间
        animatorSet.start(); //启动
        Message handlemsg = new Message();
        handlemsg.what = 1;
        mHandler.sendMessage(handlemsg);
        translationY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.e("slkdfhjksjss", "========");

            }
        });
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                view_anim.setVisibility(View.GONE);

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

    }

    private int handlerSize = 0;
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    if (handlerSize < 1000) {
                        handlerSize += 1;
                        Message handlemsg = new Message();
                        handlemsg.what = 1;
                        mHandler.sendMessageDelayed(handlemsg, 1);
                        view_anim.start(rotationBetweenLines);
                    } else {
                        handlerSize = 0;
                        view_anim.end();
                    }

                    break;
            }
        }
    };

    //获取角度
    public int getRotationBetweenLines(float centerX, float centerY, float xInView, float yInView) {
        double rotation = 0;

        double k1 = (double) (centerY - centerY) / (centerX * 2 - centerX);
        double k2 = (double) (yInView - centerY) / (xInView - centerX);
        double tmpDegree = Math.atan((Math.abs(k1 - k2)) / (1 + k1 * k2)) / Math.PI * 180;

        if (xInView > centerX && yInView < centerY) {  //第一象限
            rotation = 90 - tmpDegree;
        } else if (xInView > centerX && yInView > centerY) //第二象限
        {
            rotation = 90 + tmpDegree;
        } else if (xInView < centerX && yInView > centerY) { //第三象限
            rotation = 270 - tmpDegree;
        } else if (xInView < centerX && yInView < centerY) { //第四象限
            rotation = 270 + tmpDegree;
        } else if (xInView == centerX && yInView < centerY) {
            rotation = 0;
        } else if (xInView == centerX && yInView > centerY) {
            rotation = 180;
        }

        return (int) rotation;
    }

那么整体就可以实现了。

demo下载地址:https://download.csdn.net/download/greatdaocaoren/12532060

 

猜你喜欢

转载自blog.csdn.net/greatdaocaoren/article/details/106825116