package com.kaichunlin.transition.internal;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.animation.Interpolator;
import com.kaichunlin.transition.R;
import com.kaichunlin.transition.util.TransitionStateLogger;
/**
*/
public abstract class TransitionController<T extends TransitionController> {
public static final float DEFAULT_START = 0f;
public static final float DEFAULT_END = 1f;
private String mId;
View mTarget;
float mStart = DEFAULT_START;
float mEnd = DEFAULT_END;
float mProgressWidth;
boolean mStarted;
long mStartDelay;
long mDuration;
long mTotalDuration;
long mLastTime;
boolean mSetup;
Interpolator mInterpolator;
boolean mUpdateStateAfterUpdateProgress;
boolean mEnable = true;
boolean mReverse;
/**
* @param target the view this object should manipulate
*/
public TransitionController(@Nullable View target) {
this.mTarget = target;
}
public void setId(@NonNull String id) {
mId = id;
}
public String getId() {
if (mId == null) {
mId = toString();
}
return mId;
}
/**
* Starts the transition
*/
public void start() {
mLastTime = -1;
mSetup = true;
}
/**
* @param progress
*/
protected abstract void updateProgress(float progress);
/**
* Ends the transition
*/
public void end() {
mStarted = false;
}
protected void updateProgressWidth() {
mProgressWidth = Math.abs(mEnd - mStart);
}
/**
* Defaults to [0..1] if not set
*
* @param start the start of the applicable transition range
* @param end the end of the applicable transition range
* @return
*/
public T setRange(float start, float end) {
this.mStart = start;
this.mEnd = end;
updateProgressWidth();
return self();
}
/**
* @return the start value for the applicable transition range
*/
public float getStart() {
return mStart;
}
public T setStart(float mStart) {
this.mStart = mStart;
updateProgressWidth();
return self();
}
/**
* @return the end value for the applicable transition range
*/
public float getEnd() {
return mEnd;
}
public T setEnd(float end) {
this.mEnd = end;
updateProgressWidth();
return self();
}
public View getTarget() {
return mTarget;
}
/**
* Reverse how the transition is applied, such that the transition previously performed when progress=start of range is only performed when progress=end of range
*
* @return
*/
public T reverse() {
String id = getId();
String REVERSE = "_REVERSE";
if (id.endsWith(REVERSE)) {
setId(id.substring(0, id.length() - REVERSE.length()));
}
float start = mStart;
float end = mEnd;
mStart = end;
mEnd = start;
mReverse = !mReverse;
return self();
}
public boolean isReverse() {
return mReverse;
}
/**
* @param target the view this controller should manipulate
* @return
*/
public T setTarget(@Nullable View target) {
this.mTarget = target;
return self();
}
/**
* @param interpolator the Interpolator this controller should be when transiting a view
*/
public void setInterpolator(@Nullable Interpolator interpolator) {
mInterpolator = interpolator;
}
/**
* @param updateStateAfterUpdateProgress whether or not to update a controller's enable state after each {@link #updateProgress(float)} call
*/
public void setUpdateStateAfterUpdateProgress(boolean updateStateAfterUpdateProgress) {
mUpdateStateAfterUpdateProgress = updateStateAfterUpdateProgress;
}
/**
* Enables or disables the controller
*
* @param enable
*/
public void setEnable(boolean enable) {
mEnable = enable;
}
/**
* TODO hack to make ViewPager work
*
* @return is the controlled enabled
*/
public boolean isEnable() {
return mEnable;
}
public TransitionStateLogger getTransitionStateHolder() {
TransitionStateLogger logger = (TransitionStateLogger) getTarget().getTag(R.id.debug_id);
if (logger == null) {
logger = new TransitionStateLogger(getId());
getTarget().setTag(R.id.debug_id, logger);
}
return logger;
}
@CheckResult
@Override
public TransitionController clone() {
try {
return (TransitionController) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
protected abstract T self();
}