blob: ae2e4aaec35be36dcbfe8bf515b2a060b52662b5 [file] [log] [blame]
/*
* 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.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;
/**
* 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 int mSlideEdge = Gravity.BOTTOM;
private interface CalculateSlide {
/** Returns the translation value for view when it goes out of the scene */
float getGoneX(ViewGroup sceneRoot, View view);
/** Returns the translation value for view when it goes out of the scene */
float getGoneY(ViewGroup sceneRoot, View view);
}
private static abstract class CalculateSlideHorizontal implements CalculateSlide {
@Override
public float getGoneY(ViewGroup sceneRoot, View view) {
return view.getTranslationY();
}
}
private static abstract class CalculateSlideVertical implements CalculateSlide {
@Override
public float getGoneX(ViewGroup sceneRoot, View view) {
return view.getTranslationX();
}
}
private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
@Override
public float getGoneX(ViewGroup sceneRoot, View view) {
return view.getTranslationX() - sceneRoot.getWidth();
}
};
private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
@Override
public float getGoneY(ViewGroup sceneRoot, View view) {
return view.getTranslationY() - sceneRoot.getHeight();
}
};
private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
@Override
public float getGoneX(ViewGroup sceneRoot, View view) {
return view.getTranslationX() + sceneRoot.getWidth();
}
};
private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
@Override
public float getGoneY(ViewGroup sceneRoot, View view) {
return view.getTranslationY() + sceneRoot.getHeight();
}
};
/**
* Constructor using the default {@link Gravity#BOTTOM}
* slide edge direction.
*/
public Slide() {
setSlideEdge(Gravity.BOTTOM);
}
/**
* Constructor using the provided slide edge direction.
*/
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);
}
/**
* 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}.
* @attr ref android.R.styleable#Slide_slideEdge
*/
public void setSlideEdge(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;
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}.
* @attr ref android.R.styleable#Slide_slideEdge
*/
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);
float startY = mSlideCalculator.getGoneY(sceneRoot, view);
return TranslationAnimationCreator
.createAnimation(view, endValues, position[0], position[1],
startX, startY, endX, endY, sDecelerate);
}
@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);
float endY = mSlideCalculator.getGoneY(sceneRoot, view);
return TranslationAnimationCreator
.createAnimation(view, startValues, position[0], position[1],
startX, startY, endX, endY, sAccelerate);
}
}