1 package com.android.launcher3.anim; 2 3 import android.animation.Animator; 4 import android.animation.AnimatorListenerAdapter; 5 import android.animation.ValueAnimator; 6 import android.graphics.Outline; 7 import android.graphics.Rect; 8 import android.view.View; 9 import android.view.ViewOutlineProvider; 10 11 /** 12 * A {@link ViewOutlineProvider} that has helper functions to create reveal animations. 13 * This class should be extended so that subclasses can define the reveal shape as the 14 * animation progresses from 0 to 1. 15 */ 16 public abstract class RevealOutlineAnimation extends ViewOutlineProvider { 17 protected Rect mOutline; 18 protected float mOutlineRadius; 19 RevealOutlineAnimation()20 public RevealOutlineAnimation() { 21 mOutline = new Rect(); 22 } 23 24 /** Returns whether elevation should be removed for the duration of the reveal animation. */ shouldRemoveElevationDuringAnimation()25 abstract boolean shouldRemoveElevationDuringAnimation(); 26 /** Sets the progress, from 0 to 1, of the reveal animation. */ setProgress(float progress)27 abstract void setProgress(float progress); 28 createRevealAnimator(final View revealView, boolean isReversed)29 public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed) { 30 ValueAnimator va = 31 isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f); 32 final float elevation = revealView.getElevation(); 33 34 va.addListener(new AnimatorListenerAdapter() { 35 private boolean mIsClippedToOutline; 36 private ViewOutlineProvider mOldOutlineProvider; 37 38 public void onAnimationStart(Animator animation) { 39 mIsClippedToOutline = revealView.getClipToOutline(); 40 mOldOutlineProvider = revealView.getOutlineProvider(); 41 42 revealView.setOutlineProvider(RevealOutlineAnimation.this); 43 revealView.setClipToOutline(true); 44 if (shouldRemoveElevationDuringAnimation()) { 45 revealView.setTranslationZ(-elevation); 46 } 47 } 48 49 public void onAnimationEnd(Animator animation) { 50 revealView.setOutlineProvider(mOldOutlineProvider); 51 revealView.setClipToOutline(mIsClippedToOutline); 52 if (shouldRemoveElevationDuringAnimation()) { 53 revealView.setTranslationZ(0); 54 } 55 } 56 57 }); 58 59 va.addUpdateListener(v -> { 60 float progress = (Float) v.getAnimatedValue(); 61 setProgress(progress); 62 revealView.invalidateOutline(); 63 }); 64 return va; 65 } 66 67 @Override getOutline(View v, Outline outline)68 public void getOutline(View v, Outline outline) { 69 outline.setRoundRect(mOutline, mOutlineRadius); 70 } 71 getRadius()72 public float getRadius() { 73 return mOutlineRadius; 74 } 75 getOutline(Rect out)76 public void getOutline(Rect out) { 77 out.set(mOutline); 78 } 79 } 80