Android 水波纹特效

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/github_34402358/article/details/82050113

先看一下动画效果:第一次上传gif图片 先录的mp4视频 后来转的gif
这里写图片描述
Android动画在这里就不详细讲了,网上一大把,不清楚的可以去看看。这里只讲这个动画的视线逻辑。
这个动画这里分四个部分:
1.最底部图片心跳动画
2.水波纹扩散动画
3.头像出现的时机动画
4.中间个人头像动画

在这里先讲第一部分:最底部图片心跳动画

 int size = mList.length;
        animPoints = new Animation[size];
        /**
         * 五个小点 动画显示
         * */
        for (int i = 0; i < size; i++) {
            final int j = i;
            LayoutParams mSmallCircleParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            if (j == 0) {
                mSmallCircleParams.rightMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_140);
                mSmallCircleParams.gravity = Gravity.RIGHT;
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_380);
            } else if (j == 1) {
                mSmallCircleParams.rightMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_75);
                mSmallCircleParams.gravity = Gravity.RIGHT;
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_89);
            } else if (j == 2) {
                mSmallCircleParams.leftMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_17);
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_150);
            } else if (j == 3) {
                mSmallCircleParams.leftMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_39);
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_240);
            } else if (j == 4) {
                mSmallCircleParams.rightMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_112);
                mSmallCircleParams.gravity = Gravity.RIGHT;
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_224);
            }

            ImageView mSmallCircleView = new ImageView(getContext());
            mSmallCircleView.setImageResource(mList[j]);
            addView(mSmallCircleView, mSmallCircleParams);

            /**加载动画*/
            animPoints[j] = AnimationUtils.loadAnimation(getContext(), R.anim.anim_the_heartbeat);
            mSmallCircleView.startAnimation(animPoints[j]);

            animPoints[j].setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    if (mAnimationProgressListener != null) {
                        mAnimationProgressListener.startAnimation();
                    }
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    if (mAnimationProgressListener != null) {
                        mAnimationProgressListener.endAnimation();
                    }

                    if (null != animPoints && null != animPoints[j]) {
                        animPoints[j].cancel();
                    }

                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

        }

在这里先讲第二部分:水波纹扩散动画

 //布局 管理器,让圆剧中显示
        LayoutParams rippleParams = new LayoutParams((int) (2 * (rippleRadius + rippleStrokeWidth * 3)), (int) (2 * (rippleRadius + rippleStrokeWidth * 3)));
        rippleParams.gravity = Gravity.CENTER;

        //动画的集合
        ArrayList<Animator> animatorList = new ArrayList<>();

        //水波纹 缩放、渐变动画
        for (int i = 0; i < rippleAmount; i++) {

            RipplView rippleView = new RipplView(getContext());
            addView(rippleView, rippleParams);
            rippleViewList.add(rippleView);

            //伸缩动画
            float rippleScale = 6.0f;
            final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleX", 1.0f, rippleScale);
            scaleXAnimator.setRepeatCount(ValueAnimator.INFINITE);
            scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART);
            scaleXAnimator.setStartDelay(i * rippleDelay);
            animatorList.add(scaleXAnimator);

            final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleY", 1.0f, rippleScale);
            scaleYAnimator.setRepeatCount(ValueAnimator.INFINITE);
            scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART);
            scaleYAnimator.setStartDelay(i * rippleDelay);
            animatorList.add(scaleYAnimator);

            //透明度动画
            final ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rippleView, "Alpha", 1.0f, 0f);
            alphaAnimator.setRepeatCount(ValueAnimator.INFINITE);
            alphaAnimator.setRepeatMode(ObjectAnimator.RESTART);
            alphaAnimator.setStartDelay(i * rippleDelay);
            animatorList.add(alphaAnimator);
        }

        //开始动画
        animatorSet.playTogether(animatorList);
        //动画的监听
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                if (mAnimationProgressListener != null) {
                    mAnimationProgressListener.startAnimation();
                }
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                if (mAnimationProgressListener != null) {
                    mAnimationProgressListener.endAnimation();
                }
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

在这里讲第三部分:头像出现的时机动画
简单的理解就是划分了六个区域:

private final static int showNum = 5;
    private static long delayMillis = 4000;

    private int radiusP;
    private int radiusC;
    private int radiusB;
    private int pointCX;
    private int pointCY;
    private int page = 0;
    private int lastNum = 0;
    private boolean isAddShowing = false;
    private List<String> mGodHeadPhoto = new ArrayList<>();
    private Handler mHandler = new Handler();
    private UserRunnable userRunnable;
    private CircleImageView[] imageViews;
    private ObjectAnimator[] animator;

    /**
     * 设置大神头像
     */
    public void setUserPhoto(List<String> godHeadPhoto) {
        Log.e(TAG, "setUserPhoto==11==" + (null == godHeadPhoto ? 0 : godHeadPhoto.size()));
        if (null == godHeadPhoto || godHeadPhoto.isEmpty()) {
            return;
        }
        mGodHeadPhoto.addAll(godHeadPhoto);
        Log.e(TAG, "setUserPhoto==22==" + mGodHeadPhoto.size() + "==isAddShowing==" + isAddShowing);
        if (isAddShowing) {
            return;
        }
        page = 0;
        lastNum = 0;
        isAddShowing = true;
        if (radiusP <= 0 || radiusC <= 0 || radiusB <= 0 || pointCX <= 0 || pointCY <= 0) {
            this.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    RippleView.this.getViewTreeObserver().removeOnPreDrawListener(this);
                    //RippleView宽
                    int rippleW = RippleView.this.getWidth();
                    //RippleView高
                    int rippleH = RippleView.this.getHeight();
                    radiusP = ResUtil.getDimens(mContext, R.dimen.common_padding_16);
                    radiusC = ResUtil.getDimens(mContext, R.dimen.common_padding_36);
                    int padding = ResUtil.getDimens(mContext, R.dimen.common_padding_20);
                    radiusB = rippleW / 2 - radiusP - padding;
                    pointCX = rippleW / 2;
                    pointCY = rippleH / 2;

                    startShowUserList(true);
                    return true;
                }
            });
        } else {
            startShowUserList(true);
        }
    }

    /**
     * 开始显示
     *
     * @param isFirst 是否第一次显示
     */
    private void startShowUserList(boolean isFirst) {
        if (isHidden || (!isFirst && isAddShowing)) {
            return;
        }
        isAddShowing = true;
        showNextUserList();
    }

    /**
     * 获得当前显示大神list
     *
     * @return
     */
    private List<String> getCurShowList() {
        if (null == mGodHeadPhoto || mGodHeadPhoto.isEmpty()) {
            return null;
        }
        int size = mGodHeadPhoto.size();
        if (showNum >= size) {
            page = 0;
            lastNum = size;
            return mGodHeadPhoto;
        }
        int start = lastNum + page * showNum;
        if (start >= size) {
            return null;
        }
        int end = lastNum + (page + 1) * showNum;
        if (end >= size) {
            //列表已经展示结束
            page = 0;
            if (end == size) {
                lastNum = 0;
                return mGodHeadPhoto.subList(start, size);
            } else {
                lastNum = end - size;
                List<String> list = new ArrayList<>();
                list.addAll(mGodHeadPhoto.subList(start, size));
                list.addAll(mGodHeadPhoto.subList(0, lastNum));
                return list;
            }
        } else {
            page++;
            return mGodHeadPhoto.subList(start, end);
        }
    }

    /**
     * @param radiusP 五个随机大神头像半径
     * @param radiusC 中心点圆半径
     * @param radiusB 显示区域半径
     * @param pointCX 中心点x坐标
     * @param pointCY 中心点y坐标
     */
    private void addViewPhoto(int radiusP, int radiusC, int radiusB, int pointCX, int pointCY, List<String> list) {
        Log.e(TAG, "addViewPhoto==" + (null == list ? 0 : list.size()) + "==lastNum==" + lastNum + "==page==" + page + "==mGodHeadPhoto.size==" + mGodHeadPhoto.size());
        if (null != imageViews) {
            for (int i = 0; i < imageViews.length; i++) {
                if (null != imageViews[i]) {
                    RippleView.this.removeView(imageViews[i]);
                }
            }
        }
        if (userRunnable != null) {
            mHandler.removeCallbacks(userRunnable);
        }
        int size = null == list ? 0 : list.size();
        if (size == 0) {
            isAddShowing = false;
            animPhotos = null;
            imageViews = null;
            return;
        }
        animPhotos = new Animation[size];
        imageViews = new CircleImageView[size];
        animator = new ObjectAnimator[size];

        //动画控件的宽高
        for (int i = 0; i < size; i++) {
            final int k = i;
            int x1;
            int y1;
            int x2;
            int y2;
            if (k == 0) {
                /**随机按钮分四片区域显示
                 * 左上角区域
                 */
                x1 = pointCX - radiusB;
                y1 = pointCY - radiusB;

                x2 = pointCX - radiusP;
                y2 = pointCY - radiusC - radiusP;
            } else if (k == 1) {
                /**随机按钮分四片区域显示
                 * 右上角区域
                 */
                x1 = pointCX + radiusP;
                y1 = pointCY - radiusB;

                x2 = pointCX + radiusB;
                y2 = pointCY - radiusC;
            } else if (k == 2) {
                /**随机按钮分四片区域显示
                 * 左下角区域
                 */
                x1 = pointCX - radiusB;
                y1 = pointCY + radiusC + radiusP;

                x2 = pointCX - radiusP;
                y2 = pointCY + radiusB;
            } else if (k == 3) {
                /**随机按钮分四片区域显示
                 * 右下角区域
                 */
                x1 = pointCX + radiusP;
                y1 = pointCY + radiusC + radiusP;

                x2 = pointCX + radiusB;
                y2 = pointCY + radiusB;
            } else {
                int yshu = getRandomInt(Integer.MAX_VALUE) % 2;
                if (yshu == 0) {
                    /**随机按钮分四片区域显示
                     * 左中区域
                     */
                    x1 = pointCX - radiusB;
                    y1 = pointCY - radiusC + radiusP;

                    x2 = pointCX - radiusC - radiusP;
                    y2 = pointCY + radiusC - radiusP;
                } else {
                    /**随机按钮分四片区域显示 j
                     * 右中区域
                     */
                    x1 = pointCX + radiusC + radiusP;
                    y1 = pointCY - radiusC + radiusP;

                    x2 = pointCX + radiusB;
                    y2 = pointCY + radiusC - radiusP;
                }
            }
//            Log.e("addView", "addView x ==== == " + ((x2 - x1) / 2 + x1));
//            Log.e("addView", "addView y ==== == " + ((y2 - y1) / 2 + y1));
            //随机生成一个屏内的位置来显示动画

            int xs = 0;
            int ys = 0;
            boolean flag = true;
            while (flag) {
                xs = getRandomInt(Integer.MAX_VALUE) % (x2 - x1) + x1;
                ys = getRandomInt(Integer.MAX_VALUE) % (y2 - y1) + y1;
                if (isCricle(xs, ys)) {
                    flag = false;
                }
            }

            final int x = xs;
            final int y = ys;
            final String pathPhoto = list.get(k);

//            Log.e("addView", "addView x   === " + x);
//            Log.e("addView", "addView y   === " + y);
            mHandler.postDelayed(new WaitPhotoRunnable(pathPhoto, k, x, y), k * 180);

        }
        showNextUserList();
    }

deom下载地址

猜你喜欢

转载自blog.csdn.net/github_34402358/article/details/82050113