首先看一下效果图:
以上效果就是揭露动画了。
其布局如下:
其中,圆形按钮就是FloatingActionButton
,上方的图片就是ImageView
。
Android SDK为揭露动画专门提供了一个工具类ViewAnimationUtils
,其源码如下:
public final class ViewAnimationUtils {
private ViewAnimationUtils() {}
/**
* Returns an Animator which can animate a clipping circle.
*
* Any shadow cast by the View will respect the circular clip from this animator.
*
* Only a single non-rectangular clip can be applied on a View at any time.
* Views clipped by a circular reveal animation take priority over
* {@link View#setClipToOutline(boolean) View Outline clipping}.
*
* Note that the animation returned here is a one-shot animation. It cannot
* be re-used, and once started it cannot be paused or resumed. It is also
* an asynchronous animation that automatically runs off of the UI thread.
* As a result {@link Animator.AnimatorListener#onAnimationEnd(Animator)}
* will occur after the animation has ended, but it may be delayed depending
* on thread responsiveness.
*
* Note that if any start delay is set on the reveal animator, the start radius
* will not be applied to the reveal circle until the start delay has passed.
* If it's desired to set a start radius on the reveal circle during the start
* delay, one workaround could be adding an animator with the same start and
* end radius. For example:
*
* public static Animator createRevealWithDelay(View view, int centerX, int centerY, float startRadius, float endRadius) {
* Animator delayAnimator = ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, startRadius);
* delayAnimator.setDuration(delayTimeMS);
* Animator revealAnimator = ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius);
* AnimatorSet set = new AnimatorSet();
* set.playSequentially(delayAnimator, revealAnimator);
* return set;
* }
*
*
* @param view The View will be clipped to the animating circle.
* @param centerX The x coordinate of the center of the animating circle, relative to
* view
.
* @param centerY The y coordinate of the center of the animating circle, relative to
* view
.
* @param startRadius The starting radius of the animating circle.
* @param endRadius The ending radius of the animating circle.
*/
public static Animator createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius) {
return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
}
}
这个工具类中只有一个方法createCircularReveal
。
Animator createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius)
其参数的意义分别是:
- view:动画的目标view
- centerX:确定动画圆的圆点x轴位置
- centerY:确定动画圆的圆点y轴位置
- startRadius:动画开始圆半径
- endRadius:动画结束圆半径
参数设定思路:
- view,就是上面布局代码中的
ImageView
- centerX和centerY,将圆形按钮
FloatingActionButton
的中心点作为动画的圆点 - startRadius,动画的开始半径,这个可以随意设置,当然,为了效果最佳,建议将它设置为矩形图片的对角线长度
- endRadius,当动画结束时的半径,这个可以随意设置,当然,为了效果最佳,建议将它设置为圆形按钮的半径长度,货值直接设置为0
实现代码如下:
Animation animation = image.getAnimation();
if (animation != null) {
animation.cancel();
}
int[] vLocation = new int[2];//存放按钮中心店的坐标,按钮的中心点作为揭露动画的圆点
fab.getLocationInWindow(vLocation);
int centerX = vLocation[0] + fab.getWidth() / 2;
int centerY = vLocation[1] + fab.getHeight() / 2;
CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout);
//求出对角线
int hypotenuse = (int) Math.hypot(collapsingToolbarLayout.getWidth(), collapsingToolbarLayout.getHeight());
if (isShow) {
final Animator circularReveal = ViewAnimationUtils.createCircularReveal(image, centerX, centerY, hypotenuse, 0);
circularReveal.setDuration(2000);
circularReveal.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
image.setVisibility(View.GONE);
circularReveal.removeListener(this);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
circularReveal.start();
isShow = false;
} else {
final Animator circularReveal = ViewAnimationUtils.createCircularReveal(image, centerX, centerY, 0, hypotenuse);
circularReveal.setDuration(2000);
circularReveal.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
circularReveal.removeListener(this);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
image.setVisibility(View.VISIBLE);
circularReveal.start();
isShow = true;
}
[本章完...]