package carbon.animation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import carbon.R;
import carbon.internal.MathUtils;
import carbon.shadow.ShadowView;
import carbon.widget.ProgressBar;
public class AnimUtils {
private AnimUtils() {
}
interface AnimatorFactory {
Animator getAnimator();
}
public enum Style {
None(() -> null, () -> null),
Fade(AnimUtils::getFadeInAnimator, AnimUtils::getFadeOutAnimator),
Pop(AnimUtils::getPopInAnimator, AnimUtils::getPopOutAnimator),
Fly(AnimUtils::getFlyInAnimator, AnimUtils::getFlyOutAnimator),
BrightnessSaturationFade(AnimUtils::getBrightnessSaturationFadeInAnimator, AnimUtils::getBrightnessSaturationFadeOutAnimator),
ProgressWidth(AnimUtils::getProgressWidthInAnimator, AnimUtils::getProgressWidthOutAnimator);
private AnimatorFactory inAnimator;
private AnimatorFactory outAnimator;
Style(AnimatorFactory inAnimator, AnimatorFactory outAnimator) {
this.inAnimator = inAnimator;
this.outAnimator = outAnimator;
}
public Animator getInAnimator() {
return inAnimator.getAnimator();
}
public Animator getOutAnimator() {
return outAnimator.getAnimator();
}
}
public static ValueAnimator getFadeInAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new DecelerateInterpolator());
animator.setOnSetupValuesListener(() -> {
View view = animator.getTarget();
if (view.getVisibility() != View.VISIBLE)
view.setAlpha(0);
float start = view.getAlpha();
animator.setFloatValues(start, 1);
animator.setDuration((long) (200 * (1 - start)));
});
animator.addUpdateListener(valueAnimator -> {
View view = animator.getTarget();
view.setAlpha((Float) valueAnimator.getAnimatedValue());
if (view.getParent() != null)
((View) view.getParent()).postInvalidate();
});
return animator;
}
public static ValueAnimator getFadeOutAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new DecelerateInterpolator());
animator.setOnSetupValuesListener(() -> {
View view = animator.getTarget();
float start = view.getAlpha();
animator.setFloatValues(start, 0);
animator.setDuration((long) (200 * start));
});
animator.addUpdateListener(valueAnimator -> {
View view = animator.getTarget();
view.setAlpha((Float) valueAnimator.getAnimatedValue());
if (view.getParent() != null)
((View) view.getParent()).postInvalidate();
});
return animator;
}
public static Animator getPopInAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new DecelerateInterpolator());
animator.setOnSetupValuesListener(() -> {
View view = animator.getTarget();
if (view.getVisibility() != View.VISIBLE)
view.setAlpha(0);
float start = view.getAlpha();
animator.setFloatValues(start, 1);
animator.setDuration((long) (200 * (1 - start)));
});
animator.addUpdateListener(valueAnimator -> {
View view = animator.getTarget();
view.setAlpha((Float) valueAnimator.getAnimatedValue());
view.setScaleX((Float) valueAnimator.getAnimatedValue());
view.setScaleY((Float) valueAnimator.getAnimatedValue());
if (view.getParent() != null)
((View) view.getParent()).postInvalidate();
});
return animator;
}
public static Animator getPopOutAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new DecelerateInterpolator());
animator.setOnSetupValuesListener(() -> {
View view = animator.getTarget();
float start = view.getAlpha();
animator.setFloatValues(start, 0);
animator.setDuration((long) (200 * start));
});
animator.addUpdateListener(valueAnimator -> {
View view = animator.getTarget();
view.setAlpha((Float) valueAnimator.getAnimatedValue());
view.setScaleX((Float) valueAnimator.getAnimatedValue());
view.setScaleY((Float) valueAnimator.getAnimatedValue());
if (view.getParent() != null)
((View) view.getParent()).postInvalidate();
});
return animator;
}
public static ValueAnimator getFlyInAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new LinearOutSlowInInterpolator());
animator.setOnSetupValuesListener(() -> {
View view = animator.getTarget();
if (view.getVisibility() != View.VISIBLE)
view.setAlpha(0);
float start = view.getAlpha();
animator.setFloatValues(start, 1);
animator.setDuration((long) (200 * (1 - start)));
});
animator.addUpdateListener(valueAnimator -> {
View view = animator.getTarget();
view.setAlpha((Float) valueAnimator.getAnimatedValue());
view.setTranslationY(Math.min(view.getHeight() / 2, view.getResources().getDimension(R.dimen.carbon_1dip) * 50.0f) * (1 - (Float) valueAnimator.getAnimatedValue()));
if (view.getParent() != null)
((View) view.getParent()).postInvalidate();
});
return animator;
}
public static ValueAnimator getFlyOutAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new FastOutLinearInInterpolator());
animator.setOnSetupValuesListener(() -> {
View view = animator.getTarget();
float start = view.getAlpha();
animator.setFloatValues(start, 0);
animator.setDuration((long) (200 * start));
});
animator.addUpdateListener(valueAnimator -> {
View view = animator.getTarget();
view.setAlpha((Float) valueAnimator.getAnimatedValue());
view.setTranslationY(Math.min(view.getHeight() / 2, view.getResources().getDimension(R.dimen.carbon_1dip) * 50.0f) * (1 - (Float) valueAnimator.getAnimatedValue()));
if (view.getParent() != null)
((View) view.getParent()).postInvalidate();
});
return animator;
}
public static ValueAnimator getProgressWidthInAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new LinearOutSlowInInterpolator());
animator.setOnSetupValuesListener(() -> {
ProgressBar circularProgress = (ProgressBar) animator.getTarget();
final float arcWidth = circularProgress.getBarPadding() + circularProgress.getBarWidth();
float start = circularProgress.getBarWidth();
animator.setFloatValues(circularProgress.getBarWidth(), arcWidth);
animator.setDuration((long) (100 * (arcWidth - start)));
});
animator.addUpdateListener(valueAnimator -> {
ProgressBar circularProgress = (ProgressBar) animator.getTarget();
final float arcWidth = circularProgress.getBarPadding() + circularProgress.getBarWidth();
float value = (Float) valueAnimator.getAnimatedValue();
circularProgress.setBarWidth(value);
circularProgress.setBarPadding(arcWidth - value);
});
return animator;
}
public static Animator getProgressWidthOutAnimator() {
ViewAnimator animator = new ViewAnimator();
animator.setInterpolator(new FastOutLinearInInterpolator());
animator.setOnSetupValuesListener(() -> {
ProgressBar circularProgress = (ProgressBar) animator.getTarget();
float start = circularProgress.getBarWidth();
animator.setFloatValues(start, 0);
animator.setDuration((long) (100 * start));
});
animator.addUpdateListener(valueAnimator -> {
ProgressBar circularProgress = (ProgressBar) animator.getTarget();
final float arcWidth = circularProgress.getBarPadding() + circularProgress.getBarWidth();
float value = (Float) valueAnimator.getAnimatedValue();
circularProgress.setBarWidth(value);
circularProgress.setBarPadding(arcWidth - value);
});
return animator;
}
public static Animator getBrightnessSaturationFadeInAnimator() {
ViewAnimator animator = new ViewAnimator();
final AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
animator.setInterpolator(interpolator);
animator.setOnSetupValuesListener(() -> {
animator.setFloatValues(0, 1); // TODO: start values
animator.setDuration(800);
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
ColorMatrix saturationMatrix = new ColorMatrix();
ColorMatrix brightnessMatrix = new ColorMatrix();
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
ImageView imageView = (ImageView) animator.getTarget();
float fraction = animator.getAnimatedFraction();
saturationMatrix.setSaturation((Float) animator.getAnimatedValue());
float scale = 2 - interpolator.getInterpolation(Math.min(fraction * 4 / 3, 1));
brightnessMatrix.setScale(scale, scale, scale, 1);
saturationMatrix.preConcat(brightnessMatrix);
imageView.setColorFilter(new ColorMatrixColorFilter(saturationMatrix));
imageView.setAlpha(interpolator.getInterpolation(Math.min(fraction * 2, 1)));
if (imageView.getParent() != null)
((View) imageView.getParent()).postInvalidate();
}
});
return animator;
}
public static Animator getBrightnessSaturationFadeOutAnimator() {
ViewAnimator animator = new ViewAnimator();
final AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
animator.setInterpolator(interpolator);
animator.setOnSetupValuesListener(() -> {
animator.setFloatValues(1, 0);
animator.setDuration(800);
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
ColorMatrix saturationMatrix = new ColorMatrix();
ColorMatrix brightnessMatrix = new ColorMatrix();
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
ImageView imageView = (ImageView) animator.getTarget();
float fraction = animator.getAnimatedFraction();
saturationMatrix.setSaturation((Float) animator.getAnimatedValue());
float scale = 2 - interpolator.getInterpolation(Math.min((1 - fraction) * 4 / 3, 1));
brightnessMatrix.setScale(scale, scale, scale, 1);
saturationMatrix.preConcat(brightnessMatrix);
imageView.setColorFilter(new ColorMatrixColorFilter(saturationMatrix));
imageView.setAlpha(interpolator.getInterpolation(Math.min((1 - fraction) * 2, 1)));
if (imageView.getParent() != null)
((View) imageView.getParent()).postInvalidate();
}
});
return animator;
}
public static int lerpColor(float interpolation, int val1, int val2) {
int a = (int) MathUtils.lerp(val1 >> 24, val2 >> 24, interpolation);
int r = (int) MathUtils.lerp((val1 >> 16) & 0xff, (val2 >> 16) & 0xff, interpolation);
int g = (int) MathUtils.lerp((val1 >> 8) & 0xff, (val2 >> 8) & 0xff, interpolation);
int b = (int) MathUtils.lerp(val1 & 0xff, val2 & 0xff, interpolation);
return Color.argb(a, r, g, b);
}
public static void setupElevationAnimator(StateAnimator stateAnimator, final ShadowView view) {
{
final ValueAnimator animator = ValueAnimator.ofFloat(0, 0);
animator.setDuration(200);
animator.setInterpolator(new FastOutSlowInInterpolator());
Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
animator.setFloatValues(view.getTranslationZ(), ((View) view).getResources().getDimension(R.dimen.carbon_translationButton));
}
};
animator.addUpdateListener(animation -> view.setTranslationZ((Float) animation.getAnimatedValue()));
stateAnimator.addState(new int[]{android.R.attr.state_pressed}, animator, animatorListener);
}
{
final ValueAnimator animator = ValueAnimator.ofFloat(0, 0);
animator.setDuration(200);
animator.setInterpolator(new FastOutSlowInInterpolator());
Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
animator.setFloatValues(view.getTranslationZ(), 0);
}
};
animator.addUpdateListener(animation -> view.setTranslationZ((Float) animation.getAnimatedValue()));
stateAnimator.addState(new int[]{-android.R.attr.state_pressed, android.R.attr.state_enabled}, animator, animatorListener);
}
{
final ValueAnimator animator = ValueAnimator.ofFloat(0, 0);
animator.setDuration(200);
animator.setInterpolator(new FastOutSlowInInterpolator());
Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
animator.setFloatValues(view.getElevation(), 0);
}
};
animator.addUpdateListener(animation -> view.setTranslationZ((Float) animation.getAnimatedValue()));
stateAnimator.addState(new int[]{android.R.attr.state_enabled}, animator, animatorListener);
}
{
final ValueAnimator animator = ValueAnimator.ofFloat(0, 0);
animator.setDuration(200);
animator.setInterpolator(new FastOutSlowInInterpolator());
Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
animator.setFloatValues(view.getTranslationZ(), -view.getElevation());
}
};
animator.addUpdateListener(animation -> view.setTranslationZ((Float) animation.getAnimatedValue()));
stateAnimator.addState(new int[]{-android.R.attr.state_enabled}, animator, animatorListener);
}
}
}