package mbanje.kurt.fabbutton;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
/**
* Created by kurt on 21 02 2015 .
*/
public class FabUtil {
public static final float INDETERMINANT_MIN_SWEEP = 15f;
public static final int ANIMATION_STEPS = 4;
/**
* the animation callback interface that should be used by classes that want to listen for events from the library animations
*/
public static interface OnFabValueCallback{
public void onIndeterminateValuesChanged(float indeterminateSweep,float indeterminateRotateOffset,float startAngle,float progress);
}
/**
* Creates the starting angle animator for the circleview
* @param view the view that the animator is to be attached too
* @param from animate from value
* @param to animate to value
* @param callback the callback interface for animations
* @return ValueAnimator instance
*/
public static ValueAnimator createStartAngleAnimator(final View view,float from,float to,final OnFabValueCallback callback){
ValueAnimator animator = ValueAnimator.ofFloat(from, to);
animator.setDuration(5000);
animator.setInterpolator(new DecelerateInterpolator(2));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float startAngle = (Float) animation.getAnimatedValue();
callback.onIndeterminateValuesChanged(-1,-1,startAngle,-1);
view.invalidate();
}
});
return animator;
}
/**
* Creates a progress animator
* @param view the view that the animator is to be attached too
* @param from animate from value
* @param to animate to value
* @param callback the callback interface for animations
* @return ValueAnimator instance
*/
public static ValueAnimator createProgressAnimator(final View view,float from,float to,final OnFabValueCallback callback){
ValueAnimator animator = ValueAnimator.ofFloat(from, to);
animator.setDuration(500);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float actualProgress = (Float) animation.getAnimatedValue();
callback.onIndeterminateValuesChanged(-1,-1,-1,actualProgress);
view.invalidate();
}
});
return animator;
}
/**
* Creates a progress animator
* @param view the view that the animator is to be attached too
* @param step animation steps of the prgress animation
* @param animDuration duration of the animation i.e. 1 cycle
* @param callback the callback interface for animations
* @return AnimatorSet instance
*/
public static AnimatorSet createIndeterminateAnimator(final View view,float step,int animDuration, final OnFabValueCallback callback){
final float maxSweep = 360f*(ANIMATION_STEPS-1)/ANIMATION_STEPS + INDETERMINANT_MIN_SWEEP;
final float start = -90f + step*(maxSweep-INDETERMINANT_MIN_SWEEP);
// Extending the front of the arc
ValueAnimator frontEndExtend = ValueAnimator.ofFloat(INDETERMINANT_MIN_SWEEP, maxSweep);
frontEndExtend.setDuration(animDuration/ANIMATION_STEPS/2);
frontEndExtend.setInterpolator(new DecelerateInterpolator(1));
frontEndExtend.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float indeterminateSweep = (Float) animation.getAnimatedValue();
callback.onIndeterminateValuesChanged(indeterminateSweep,-1,-1,-1);
view.invalidate();
}
});
// Overall rotation
ValueAnimator rotateAnimator1 = ValueAnimator.ofFloat(step*720f/ANIMATION_STEPS, (step+.5f)*720f/ANIMATION_STEPS);
rotateAnimator1.setDuration(animDuration/ANIMATION_STEPS/2);
rotateAnimator1.setInterpolator(new LinearInterpolator());
rotateAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float indeterminateRotateOffset = (Float) animation.getAnimatedValue();
callback.onIndeterminateValuesChanged(-1,indeterminateRotateOffset,-1,-1);
}
});
// Retracting the back end of the arc
ValueAnimator backEndRetract = ValueAnimator.ofFloat(start, start+maxSweep-INDETERMINANT_MIN_SWEEP);
backEndRetract.setDuration(animDuration/ANIMATION_STEPS/2);
backEndRetract.setInterpolator(new DecelerateInterpolator(1));
backEndRetract.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float startAngle = (Float) animation.getAnimatedValue();
float indeterminateSweep = maxSweep - startAngle + start;
callback.onIndeterminateValuesChanged(indeterminateSweep,-1,startAngle,-1);
view.invalidate();
}
});
// More overall rotation
ValueAnimator rotateAnimator2 = ValueAnimator.ofFloat((step+.5f)*720f/ANIMATION_STEPS, (step+1)*720f/ANIMATION_STEPS);
rotateAnimator2.setDuration(animDuration/ANIMATION_STEPS/2);
rotateAnimator2.setInterpolator(new LinearInterpolator());
rotateAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float indeterminateRotateOffset = (Float) animation.getAnimatedValue();
callback.onIndeterminateValuesChanged(-1,indeterminateRotateOffset,-1,-1);
}
});
AnimatorSet set = new AnimatorSet();
set.play(frontEndExtend).with(rotateAnimator1);
set.play(backEndRetract).with(rotateAnimator2).after(rotateAnimator1);
return set;
}
}