android仿美团底部导航栏的点击效果——揭露动画

又是划水的一天好开心,无聊逛了逛美团,喜欢上美团底部导航栏的点击效果。感觉在哪里见过,又想不起来,后来一波百度,发现就是安卓5.0的揭露动画createCircularReveal。

这里写图片描述

什么事揭露动画,参考http://www.itdadao.com/articles/c15a1442955p0.html
看到没,大概就是这种动画效果,用的好的话,这种效果其实会很可爱。

于是,我快速的加入新建demo中,

// 显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    /**
      * createCircularReveal 方法参数
      * view 执行动画的view
      * centerX 圆心横坐标
      * centerY 圆心纵坐标
      * startRadius 动画开始时圆的半径
      * endRadius 动画结束时圆的半径
      */
    final Animator animator = ViewAnimationUtils.createCircularReveal(animateView,
                        animateView.getWidth() / 2,
                        animateView.getHeight() / 2,
                        0,
                        (float) Math.hypot(animateView.getWidth(), animateView.getHeight())); 
                        // Math.hypot确定圆的半径(算长宽的斜边长,这样半径不会太短也不会很长效果比较舒服)

    animatorHide.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        animateView.setVisibility(View.VISIBLE);
                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {

                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                });
    animatorHide.setDuration(5000);
    animatorHide.start();
} else {
    animateView.setVisibility(View.VISIBLE);
}
animateView.setEnabled(true);

使用时直接调用:

CircleAnimateUtils.handleAnimate(iv);

这样仿美团底部导航栏的点击动画就实现了,超简单吧。

接着无聊。。。发现揭露动画效果只能实现在5.0以上的手机,5.0以下的没有这个效果。如果是我做的话,5.0以下就不管了,但是美团没有这么懒,成功实现5.0以下的揭露动画。

究竟是如何实现的,本大王不服,噼里啪啦百度一波,发现了一个可爱的第三方:
https://github.com/zhangke3016/TranslationCompat

里面的CircularRevealLayout直接拖过来用了:

public class CircularRevealLayout extends FrameLayout {

    private Path path;
    private float centerX;
    private float centerY;
    private float revealRadius;
    private boolean isRunning;
    private View childView;
    private float startRadius;
    private float endRadius;

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

    public CircularRevealLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircularRevealLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        path = new Path();
    }


    public void setChildView(View childView) {
        this.childView = childView;
    }

    public void setCenterX(float centerX) {
        this.centerX = centerX;
    }

    public void setCenterY(float centerY) {
        this.centerY = centerY;
    }

    public void setStartRadius(float startRadius) {
        this.startRadius = startRadius;
    }

    public void setEndRadius(float endRadius) {
        this.endRadius = endRadius;
    }

    public void setRevealRadius(float revealRadius) {
        this.revealRadius = revealRadius;

        invalidate();

    }

    public Animator getAnimator() {
        ObjectAnimator reveal = ObjectAnimator.ofFloat(this, "revealRadius", startRadius, endRadius);

        reveal.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                animationStart(animator);
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                animationEnd(animator);
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                animationCancel(animator);
            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

        return reveal;
    }

    private void animationStart(Animator animator) {
        isRunning = true;
    }

    private void animationEnd(Animator animator) {
        isRunning = false;
    }

    private void animationCancel(Animator animator) {
        isRunning = false;
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        if (isRunning && childView == child) {
            final int state = canvas.save();

            path.reset();
            path.addCircle(centerX, centerY, revealRadius, Path.Direction.CW);

            canvas.clipPath(path);

            boolean isInvalided = super.drawChild(canvas, child, drawingTime);

            canvas.restoreToCount(state);

            return isInvalided;
        }

        return super.drawChild(canvas, child, drawingTime);
    }


    public static class Builder {

        private View view;
        private float centerX;
        private float centerY;
        private float startRadius;
        private float endRadius;

        public Builder(View view) {
            this.view = view;
        }

        public static Builder on(View view) {
            return new Builder(view);
        }

        public Builder centerX(float centerX) {
            this.centerX = centerX;
            return this;
        }

        public Builder centerY(float centerY) {
            this.centerY = centerY;
            return this;
        }

        public Builder startRadius(float startRadius) {
            this.startRadius = startRadius;
            return this;
        }

        public Builder endRadius(float endRadius) {
            this.endRadius = endRadius;
            return this;
        }

        private void setParameter(CircularRevealLayout layout) {
            layout.setCenterX(centerX);
            layout.setCenterY(centerY);
            layout.setStartRadius(startRadius);
            layout.setEndRadius(endRadius);
            layout.setChildView(view);

        }

        public Animator create() {

            if (view.getParent() != null && view.getParent() instanceof CircularRevealLayout) {

                CircularRevealLayout layout = ((CircularRevealLayout) view.getParent());

                setParameter(layout);

                return layout.getAnimator();
            }

            CircularRevealLayout layout = new CircularRevealLayout(view.getContext());

            if (Build.VERSION.SDK_INT >= 11) {
                layout.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
            }

            setParameter(layout);


            ViewGroup.LayoutParams params = view.getLayoutParams();
            ViewGroup parent = (ViewGroup) view.getParent();
            int index = 0;


            if (parent != null) {
                index = parent.indexOfChild(view);
                parent.removeView(view);
            }

            layout.addView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

            if (parent != null) {
                parent.addView(layout, index, params);
            }

            return layout.getAnimator();

        }
    }
}

牛逼吧,反正我暂时还不会写,只会copy.

public class CircleAnimateUtils {

    public static void handleAnimate(final View animateView) {
        Animator animator = CircularRevealLayout.Builder.on(animateView)
                .centerX(animateView.getWidth() / 2)
                .centerY(animateView.getHeight() / 2)
                .startRadius(0)
                .endRadius((float) Math.hypot(animateView.getWidth(), animateView.getHeight()))
                .create();

        mAnimator.setDuration(5000);
        mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());      
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }

            @Override
            public void onAnimationStart(Animator animation) {
                animateView.setVisibility(View.VISIBLE);
                super.onAnimationStart(animation);
            }
        });
        mAnimator.start();
     }
 }

使用的时候直接调用 CircleAnimateUtils.handleAnimate(iv);

源码:https://github.com/jjjSilence/jjjPlus/tree/%E5%B0%81%E8%A3%85
仿美团底部导航栏点击——揭露动画

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值