package com.kaichunlin.transition;
import android.support.annotation.FloatRange;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Defines how a cascading transition should be applied for each child of a ViewGroup, this is used for
* {@link ViewTransitionBuilder#transitViewGroup(ViewTransitionBuilder.ViewGroupTransition, Cascade)}.
* <br>
* There are 3 different type:
* <br>
* 1. STAGGERED, where effects would interleave with each other, the length of the effect = getTransitionEnd() - getCascadeEnd():
* <br>
* <pre> child 0: |------|</pre>
* <br>
* <pre> child 1: |------|</pre>
* <br>
* <pre> child 2: |------|</pre>
* <br>
* 2. RUN_TO_THE_END, where each effect would run to getTransitionEnd(), disregarding when it started:
* <br>
* <pre> child 0: |--------------|<pre>
* <br>
* <pre> child 1: |----------|<pre>
* <br>
* <pre> child 2: |------|<pre>
* <br>
* 3. SEQUENTIAL, where each effect would run to complete before playing the next effect:
* <br>
* Effect would be run as:
* <br>
* <pre> child 0: |----|<pre>
* <br>
* <pre> child 1: |----|<pre>
* <br>
* <pre> child 2: |----|<pre>
*/
public class Cascade implements ViewTransitionBuilder.ViewGroupTransition {
private static final Interpolator DEFAULT_INTERPOLATOR = new LinearInterpolator();
public static final int STAGGERED = 0;
public static final int RUN_TO_THE_END = 1;
public static final int SEQUENTIAL = 2;
@IntDef({STAGGERED, RUN_TO_THE_END, SEQUENTIAL})
@Retention(RetentionPolicy.SOURCE)
@interface Type {
}
public final @Type int type;
public final Interpolator interpolator;
float mCascadeStart;
//end of the cascade, i.e. the last child will start the effect at this point
public final float cascadeEnd;
//end of transition effect, i.e. all effects will stop at this point
float mTransitionEnd = 1f;
boolean mReverse;
/**
* @param cascadeEnd This value should never be 1, otherwise no transition will be applied to the last child.
*/
public Cascade(@Type int type, @FloatRange(from = 0.0, to = 1.0) float cascadeEnd) {
this(type, cascadeEnd, DEFAULT_INTERPOLATOR);
}
/**
* @param cascadeEnd This value should never be 1, otherwise no transition will be applied to the last child.
*/
public Cascade(@Type int type, @FloatRange(from = 0.0, to = 1.0) float cascadeEnd, @NonNull Interpolator interpolator) {
this.type = type;
this.cascadeEnd = cascadeEnd;
this.interpolator = interpolator;
}
public int getType() {
return type;
}
public Interpolator getInterpolator() {
return interpolator;
}
public float getCascadeEnd() {
return cascadeEnd;
}
public Cascade cascadeStart(@FloatRange(from = 0.0, to = 1.0) float cascadeStart) {
this.mCascadeStart = cascadeStart;
return this;
}
public float getCascadeStart() {
return mCascadeStart;
}
public Cascade transitionEnd(@FloatRange(from = 0.0, to = 1.0) float transitionEnd) {
this.mTransitionEnd = transitionEnd;
return this;
}
public float getTransitionEnd() {
return mTransitionEnd;
}
public Cascade reverse() {
this.mReverse = true;
return this;
}
public boolean isReverse() {
return mReverse;
}
/**
* Configures a {@link ViewTransitionBuilder} per the Cascade's Type.
*
* @param builder
* @param config Contains context about the view being configured.
*/
@Override
public void transit(ViewTransitionBuilder builder, ViewTransitionBuilder.ViewGroupTransitionConfig config) {
float cascadeLength = cascadeEnd - mCascadeStart;
float minEffectLength = mTransitionEnd - cascadeEnd;
float fraction = cascadeLength / (config.total - 1);
float rangeStart = mCascadeStart + (mReverse ? config.total - 1 - config.getIndex() : config.getIndex()) * fraction;
float rangeEnd;
switch (type) {
case STAGGERED:
rangeEnd = rangeStart + minEffectLength;
break;
case RUN_TO_THE_END:
rangeEnd = mTransitionEnd;
break;
case SEQUENTIAL:
rangeEnd = rangeStart + fraction;
if (rangeEnd > mTransitionEnd) {
rangeEnd = mTransitionEnd;
}
break;
default:
throw new IllegalArgumentException();
}
builder.range(interpolator.getInterpolation(rangeStart), interpolator.getInterpolation(rangeEnd));
}
}