270 lines
10 KiB
Java
270 lines
10 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
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;
|
|
|
|
/**
|
|
* This transition tracks changes to the visibility of target views in the
|
|
* start and end scenes and moves views in or out from one of the edges of the
|
|
* scene. Visibility is determined by both the
|
|
* {@link View#setVisibility(int)} state of the view as well as whether it
|
|
* is parented in the current view hierarchy. Disappearing Views are
|
|
* limited as described in {@link Visibility#onDisappear(android.view.ViewGroup,
|
|
* TransitionValues, int, TransitionValues, int)}.
|
|
*/
|
|
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;
|
|
|
|
/** @hide */
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
@IntDef({Gravity.LEFT, Gravity.TOP, Gravity.RIGHT, Gravity.BOTTOM, Gravity.START, Gravity.END})
|
|
public @interface GravityFlag {}
|
|
|
|
private interface CalculateSlide {
|
|
|
|
/** Returns the translation value for view when it goes out of the scene */
|
|
float getGoneX(ViewGroup sceneRoot, View view, float fraction);
|
|
|
|
/** Returns the translation value for view when it goes out of the scene */
|
|
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;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Constructor using the default {@link Gravity#BOTTOM}
|
|
* slide edge direction.
|
|
*/
|
|
public Slide() {
|
|
setSlideEdge(Gravity.BOTTOM);
|
|
}
|
|
|
|
/**
|
|
* Constructor using the provided slide edge direction.
|
|
*/
|
|
public Slide(@GravityFlag 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);
|
|
}
|
|
|
|
/**
|
|
* Change the edge that Views appear and disappear from.
|
|
*
|
|
* @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of
|
|
* {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
|
|
* {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
|
|
* {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
|
|
* @attr ref android.R.styleable#Slide_slideEdge
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* Returns the edge that Views appear and disappear from.
|
|
*
|
|
* @return the edge of the scene to use for Views appearing and disappearing. One of
|
|
* {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
|
|
* {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
|
|
* {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
|
|
* @attr ref android.R.styleable#Slide_slideEdge
|
|
*/
|
|
@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);
|
|
}
|
|
|
|
/** @hide */
|
|
public void setSlideFraction(float slideFraction) {
|
|
mSlideFraction = slideFraction;
|
|
}
|
|
}
|