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