package com.github.florent37.expectanim;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.animation.Interpolator;
import com.github.florent37.expectanim.listener.AnimationEndListener;
import com.github.florent37.expectanim.listener.AnimationStartListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Created by florentchampigny on 17/02/2017.
*/
public class ExpectAnim {
private static final long DEFAULT_DURATION = 300l;
private List<ViewExpectation> expectationList;
private View anyView;
private List<View> viewToMove;
private ViewCalculator viewCalculator;
private AnimatorSet animatorSet;
private WeakReference<AnimationEndListener> endListenerWeakReference;
private WeakReference<AnimationStartListener> startListenerWeakReference;
@Nullable
private Interpolator interpolator;
private Long duration = DEFAULT_DURATION;
public ExpectAnim() {
this.expectationList = new ArrayList<>();
this.viewToMove = new ArrayList<>();
this.viewCalculator = new ViewCalculator();
}
public ViewExpectation expect(View view) {
this.anyView = view;
final ViewExpectation viewExpectation = new ViewExpectation(this, view);
expectationList.add(viewExpectation);
return viewExpectation;
}
private ExpectAnim calculate() {
if (animatorSet == null) {
animatorSet = new AnimatorSet();
if (interpolator != null) {
animatorSet.setInterpolator(interpolator);
}
animatorSet.setDuration(duration);
final List<Animator> animatorList = new ArrayList<>();
final List<ViewExpectation> expectationsToCalculate = new ArrayList<>();
//"ViewDependencies" = récupérer toutes les vues des "Expectations"
for (ViewExpectation viewExpectation : expectationList) {
viewExpectation.calculateDependencies();
viewToMove.add(viewExpectation.getViewToMove());
expectationsToCalculate.add(viewExpectation);
viewCalculator.setExpectationForView(viewExpectation.getViewToMove(), viewExpectation);
}
while (!expectationsToCalculate.isEmpty()) {
//pour chaque expectation dans "Expectations"
final Iterator<ViewExpectation> iterator = expectationsToCalculate.iterator();
while (iterator.hasNext()) {
final ViewExpectation viewExpectation = iterator.next();
//regarder si une de ces dépendance est dans "ViewDependencies"
if (!hasDependency(viewExpectation)) {
//si non
viewExpectation.calculate(viewCalculator);
animatorList.addAll(viewExpectation.getAnimations());
final View view = viewExpectation.getViewToMove();
viewToMove.remove(view);
viewCalculator.wasCalculated(viewExpectation);
iterator.remove();
} else {
//si oui, attendre le prochain tour
}
}
}
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
notifyListenerEnd();
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
notifyListenerStart();
}
});
animatorSet.playTogether(animatorList);
}
return this;
}
private void notifyListenerStart() {
if (startListenerWeakReference != null) {
final AnimationStartListener listener = startListenerWeakReference.get();
if (listener != null) {
listener.onAnimationStart(ExpectAnim.this);
}
}
}
private void notifyListenerEnd() {
if (endListenerWeakReference != null) {
final AnimationEndListener listener = endListenerWeakReference.get();
if (listener != null) {
listener.onAnimationEnd(ExpectAnim.this);
}
}
}
public ExpectAnim start() {
executeAfterDraw(anyView, new Runnable() {
@Override
public void run() {
calculate();
animatorSet.start();
}
});
return this;
}
private boolean hasDependency(ViewExpectation viewExpectation) {
final List<View> dependencies = viewExpectation.getDependencies();
if (!dependencies.isEmpty()) {
for (View view : viewToMove) {
if (dependencies.contains(view)) {
return true;
}
}
}
return false;
}
public void setPercent(float percent) {
calculate();
if (animatorSet != null) {
final ArrayList<Animator> anims = animatorSet.getChildAnimations();
for (Animator animator : anims) {
if (animator instanceof ValueAnimator) {
((ValueAnimator) animator).setCurrentPlayTime((long) (percent * animator.getDuration()));
}
}
}
}
public void setNow() {
executeAfterDraw(anyView, new Runnable() {
@Override
public void run() {
setPercent(1f);
}
});
}
public void executeAfterDraw(final View view, final Runnable runnable) {
view.postDelayed(runnable, 5);
}
public void reset() {
final ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "percent", 1f, 0f);
objectAnimator.setDuration(duration);
if (interpolator != null) {
objectAnimator.setInterpolator(interpolator);
}
objectAnimator.start();
}
public ExpectAnim setInterpolator(@NonNull Interpolator interpolator) {
this.interpolator = interpolator;
return this;
}
public ExpectAnim setDuration(long duration) {
this.duration = duration;
return this;
}
public ExpectAnim setEndListener(AnimationEndListener listener) {
this.endListenerWeakReference = new WeakReference<>(listener);
return this;
}
public ExpectAnim setStartListener(AnimationStartListener listener) {
this.startListenerWeakReference = new WeakReference<>(listener);
return this;
}
}