package android.transition;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import com.android.internal.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Slide extends Visibility {
private static final String TAG = "Slide";
private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
private CalculateSlide mSlideCalculator = sCalculateBottom;
private @GravityFlag int mSlideEdge = Gravity.BOTTOM;
private float mSlideFraction = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({Gravity.LEFT, Gravity.TOP, Gravity.RIGHT, Gravity.BOTTOM, Gravity.START, Gravity.END})
public @interface GravityFlag {}
private interface CalculateSlide {
float getGoneX(ViewGroup sceneRoot, View view, float fraction);
float getGoneY(ViewGroup sceneRoot, View view, float fraction);
}
private static abstract class CalculateSlideHorizontal implements CalculateSlide {
@Override
public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationY();
}
}
private static abstract class CalculateSlideVertical implements CalculateSlide {
@Override
public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationX();
}
}
private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
@Override
public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationX() - sceneRoot.getWidth() * fraction;
}
};
private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() {
@Override
public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final float x;
if (isRtl) {
x = view.getTranslationX() + sceneRoot.getWidth() * fraction;
} else {
x = view.getTranslationX() - sceneRoot.getWidth() * fraction;
}
return x;
}
};
private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
@Override
public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationY() - sceneRoot.getHeight() * fraction;
}
};
private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
@Override
public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationX() + sceneRoot.getWidth() * fraction;
}
};
private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() {
@Override
public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final float x;
if (isRtl) {
x = view.getTranslationX() - sceneRoot.getWidth() * fraction;
} else {
x = view.getTranslationX() + sceneRoot.getWidth() * fraction;
}
return x;
}
};
private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
@Override
public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationY() + sceneRoot.getHeight() * fraction;
}
};
public Slide() {
setSlideEdge(Gravity.BOTTOM);
}
public Slide(int slideEdge) {
setSlideEdge(slideEdge);
}
public Slide(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Slide);
int edge = a.getInt(R.styleable.Slide_slideEdge, Gravity.BOTTOM);
a.recycle();
setSlideEdge(edge);
}
private void captureValues(TransitionValues transitionValues) {
View view = transitionValues.view;
int[] position = new int[2];
view.getLocationOnScreen(position);
transitionValues.values.put(PROPNAME_SCREEN_POSITION, position);
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
super.captureStartValues(transitionValues);
captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
super.captureEndValues(transitionValues);
captureValues(transitionValues);
}
public void setSlideEdge(@GravityFlag int slideEdge) {
switch (slideEdge) {
case Gravity.LEFT:
mSlideCalculator = sCalculateLeft;
break;
case Gravity.TOP:
mSlideCalculator = sCalculateTop;
break;
case Gravity.RIGHT:
mSlideCalculator = sCalculateRight;
break;
case Gravity.BOTTOM:
mSlideCalculator = sCalculateBottom;
break;
case Gravity.START:
mSlideCalculator = sCalculateStart;
break;
case Gravity.END:
mSlideCalculator = sCalculateEnd;
break;
default:
throw new IllegalArgumentException("Invalid slide direction");
}
mSlideEdge = slideEdge;
SidePropagation propagation = new SidePropagation();
propagation.setSide(slideEdge);
setPropagation(propagation);
}
@GravityFlag
public int getSlideEdge() {
return mSlideEdge;
}
@Override
public Animator onAppear(ViewGroup sceneRoot, View view,
TransitionValues startValues, TransitionValues endValues) {
if (endValues == null) {
return null;
}
int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
float endX = view.getTranslationX();
float endY = view.getTranslationY();
float startX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction);
float startY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction);
return TranslationAnimationCreator
.createAnimation(view, endValues, position[0], position[1],
startX, startY, endX, endY, sDecelerate, this);
}
@Override
public Animator onDisappear(ViewGroup sceneRoot, View view,
TransitionValues startValues, TransitionValues endValues) {
if (startValues == null) {
return null;
}
int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
float startX = view.getTranslationX();
float startY = view.getTranslationY();
float endX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction);
float endY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction);
return TranslationAnimationCreator
.createAnimation(view, startValues, position[0], position[1],
startX, startY, endX, endY, sAccelerate, this);
}
public void setSlideFraction(float slideFraction) {
mSlideFraction = slideFraction;
}
}