blob: 9af65e4036795725dfafb7d91d70d4881dec46ff [file] [log] [blame]
Chet Haasefaebd8f2012-05-18 14:17:57 -07001/*
George Mountd6107a32014-03-10 16:51:16 -07002 * Copyright (C) 2014 The Android Open Source Project
Chet Haasefaebd8f2012-05-18 14:17:57 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Chet Haased82c8ac2013-08-26 14:20:16 -070016package android.transition;
Chet Haasefaebd8f2012-05-18 14:17:57 -070017
18import android.animation.Animator;
Chet Haasefaebd8f2012-05-18 14:17:57 -070019import android.animation.TimeInterpolator;
George Mount7764b922016-01-13 14:51:33 -080020import android.annotation.IntDef;
George Mountecd857b2014-06-19 07:51:08 -070021import android.content.Context;
22import android.content.res.TypedArray;
23import android.util.AttributeSet;
George Mountdc21d3b2014-06-05 09:42:48 -070024import android.view.Gravity;
Chet Haasefaebd8f2012-05-18 14:17:57 -070025import android.view.View;
26import android.view.ViewGroup;
27import android.view.animation.AccelerateInterpolator;
28import android.view.animation.DecelerateInterpolator;
George Mountecd857b2014-06-19 07:51:08 -070029import com.android.internal.R;
Chet Haasefaebd8f2012-05-18 14:17:57 -070030
George Mount7764b922016-01-13 14:51:33 -080031import java.lang.annotation.Retention;
32import java.lang.annotation.RetentionPolicy;
33
Chet Haasefaebd8f2012-05-18 14:17:57 -070034/**
George Mountd6107a32014-03-10 16:51:16 -070035 * This transition tracks changes to the visibility of target views in the
36 * start and end scenes and moves views in or out from one of the edges of the
37 * scene. Visibility is determined by both the
38 * {@link View#setVisibility(int)} state of the view as well as whether it
39 * is parented in the current view hierarchy. Disappearing Views are
40 * limited as described in {@link Visibility#onDisappear(android.view.ViewGroup,
41 * TransitionValues, int, TransitionValues, int)}.
Chet Haasefaebd8f2012-05-18 14:17:57 -070042 */
43public class Slide extends Visibility {
George Mountd6107a32014-03-10 16:51:16 -070044 private static final String TAG = "Slide";
George Mountd6107a32014-03-10 16:51:16 -070045 private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
46 private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
George Mount1f8c0112014-06-17 10:10:13 -070047 private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
George Mountd6107a32014-03-10 16:51:16 -070048 private CalculateSlide mSlideCalculator = sCalculateBottom;
George Mount7764b922016-01-13 14:51:33 -080049 private @GravityFlag int mSlideEdge = Gravity.BOTTOM;
50
51 /** @hide */
52 @Retention(RetentionPolicy.SOURCE)
53 @IntDef({Gravity.LEFT, Gravity.TOP, Gravity.RIGHT, Gravity.BOTTOM, Gravity.START, Gravity.END})
54 public @interface GravityFlag {}
George Mountd6107a32014-03-10 16:51:16 -070055
56 private interface CalculateSlide {
George Mountd6107a32014-03-10 16:51:16 -070057
George Mount1f8c0112014-06-17 10:10:13 -070058 /** Returns the translation value for view when it goes out of the scene */
59 float getGoneX(ViewGroup sceneRoot, View view);
George Mountd6107a32014-03-10 16:51:16 -070060
George Mount1f8c0112014-06-17 10:10:13 -070061 /** Returns the translation value for view when it goes out of the scene */
62 float getGoneY(ViewGroup sceneRoot, View view);
George Mountd6107a32014-03-10 16:51:16 -070063 }
64
65 private static abstract class CalculateSlideHorizontal implements CalculateSlide {
George Mountd6107a32014-03-10 16:51:16 -070066
67 @Override
George Mount1f8c0112014-06-17 10:10:13 -070068 public float getGoneY(ViewGroup sceneRoot, View view) {
69 return view.getTranslationY();
George Mountd6107a32014-03-10 16:51:16 -070070 }
71 }
72
73 private static abstract class CalculateSlideVertical implements CalculateSlide {
George Mountd6107a32014-03-10 16:51:16 -070074
75 @Override
George Mount1f8c0112014-06-17 10:10:13 -070076 public float getGoneX(ViewGroup sceneRoot, View view) {
77 return view.getTranslationX();
George Mountd6107a32014-03-10 16:51:16 -070078 }
79 }
80
81 private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
82 @Override
George Mount1f8c0112014-06-17 10:10:13 -070083 public float getGoneX(ViewGroup sceneRoot, View view) {
George Mountd6107a32014-03-10 16:51:16 -070084 return view.getTranslationX() - sceneRoot.getWidth();
85 }
86 };
87
George Mount2db3bf52014-11-19 14:05:57 -080088 private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() {
89 @Override
90 public float getGoneX(ViewGroup sceneRoot, View view) {
91 final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
92 final float x;
93 if (isRtl) {
94 x = view.getTranslationX() + sceneRoot.getWidth();
95 } else {
96 x = view.getTranslationX() - sceneRoot.getWidth();
97 }
98 return x;
99 }
100 };
101
George Mountd6107a32014-03-10 16:51:16 -0700102 private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
103 @Override
George Mount1f8c0112014-06-17 10:10:13 -0700104 public float getGoneY(ViewGroup sceneRoot, View view) {
George Mountd6107a32014-03-10 16:51:16 -0700105 return view.getTranslationY() - sceneRoot.getHeight();
106 }
107 };
108
109 private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
110 @Override
George Mount1f8c0112014-06-17 10:10:13 -0700111 public float getGoneX(ViewGroup sceneRoot, View view) {
George Mountd6107a32014-03-10 16:51:16 -0700112 return view.getTranslationX() + sceneRoot.getWidth();
113 }
114 };
115
George Mount2db3bf52014-11-19 14:05:57 -0800116 private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() {
117 @Override
118 public float getGoneX(ViewGroup sceneRoot, View view) {
119 final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
120 final float x;
121 if (isRtl) {
122 x = view.getTranslationX() - sceneRoot.getWidth();
123 } else {
124 x = view.getTranslationX() + sceneRoot.getWidth();
125 }
126 return x;
127 }
128 };
129
George Mountd6107a32014-03-10 16:51:16 -0700130 private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
131 @Override
George Mount1f8c0112014-06-17 10:10:13 -0700132 public float getGoneY(ViewGroup sceneRoot, View view) {
George Mountd6107a32014-03-10 16:51:16 -0700133 return view.getTranslationY() + sceneRoot.getHeight();
134 }
135 };
136
137 /**
George Mountdc21d3b2014-06-05 09:42:48 -0700138 * Constructor using the default {@link Gravity#BOTTOM}
George Mountd6107a32014-03-10 16:51:16 -0700139 * slide edge direction.
140 */
141 public Slide() {
George Mountdc21d3b2014-06-05 09:42:48 -0700142 setSlideEdge(Gravity.BOTTOM);
George Mountd6107a32014-03-10 16:51:16 -0700143 }
144
145 /**
146 * Constructor using the provided slide edge direction.
147 */
148 public Slide(int slideEdge) {
149 setSlideEdge(slideEdge);
150 }
151
George Mountecd857b2014-06-19 07:51:08 -0700152 public Slide(Context context, AttributeSet attrs) {
153 super(context, attrs);
154 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Slide);
155 int edge = a.getInt(R.styleable.Slide_slideEdge, Gravity.BOTTOM);
156 a.recycle();
157 setSlideEdge(edge);
158 }
159
George Mount1f8c0112014-06-17 10:10:13 -0700160 private void captureValues(TransitionValues transitionValues) {
161 View view = transitionValues.view;
162 int[] position = new int[2];
163 view.getLocationOnScreen(position);
164 transitionValues.values.put(PROPNAME_SCREEN_POSITION, position);
165 }
166
167 @Override
168 public void captureStartValues(TransitionValues transitionValues) {
169 super.captureStartValues(transitionValues);
170 captureValues(transitionValues);
171 }
172
173 @Override
174 public void captureEndValues(TransitionValues transitionValues) {
175 super.captureEndValues(transitionValues);
176 captureValues(transitionValues);
177 }
178
George Mountd6107a32014-03-10 16:51:16 -0700179 /**
180 * Change the edge that Views appear and disappear from.
George Mount1f8c0112014-06-17 10:10:13 -0700181 *
George Mountdc21d3b2014-06-05 09:42:48 -0700182 * @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of
183 * {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
George Mount2db3bf52014-11-19 14:05:57 -0800184 * {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
185 * {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
George Mountecd857b2014-06-19 07:51:08 -0700186 * @attr ref android.R.styleable#Slide_slideEdge
George Mountd6107a32014-03-10 16:51:16 -0700187 */
George Mount7764b922016-01-13 14:51:33 -0800188 public void setSlideEdge(@GravityFlag int slideEdge) {
George Mountd6107a32014-03-10 16:51:16 -0700189 switch (slideEdge) {
George Mountdc21d3b2014-06-05 09:42:48 -0700190 case Gravity.LEFT:
George Mountd6107a32014-03-10 16:51:16 -0700191 mSlideCalculator = sCalculateLeft;
192 break;
George Mountdc21d3b2014-06-05 09:42:48 -0700193 case Gravity.TOP:
George Mountd6107a32014-03-10 16:51:16 -0700194 mSlideCalculator = sCalculateTop;
195 break;
George Mountdc21d3b2014-06-05 09:42:48 -0700196 case Gravity.RIGHT:
George Mountd6107a32014-03-10 16:51:16 -0700197 mSlideCalculator = sCalculateRight;
198 break;
George Mountdc21d3b2014-06-05 09:42:48 -0700199 case Gravity.BOTTOM:
George Mountd6107a32014-03-10 16:51:16 -0700200 mSlideCalculator = sCalculateBottom;
201 break;
George Mount2db3bf52014-11-19 14:05:57 -0800202 case Gravity.START:
203 mSlideCalculator = sCalculateStart;
204 break;
205 case Gravity.END:
206 mSlideCalculator = sCalculateEnd;
207 break;
George Mountd6107a32014-03-10 16:51:16 -0700208 default:
209 throw new IllegalArgumentException("Invalid slide direction");
210 }
George Mountecd857b2014-06-19 07:51:08 -0700211 mSlideEdge = slideEdge;
George Mountd6107a32014-03-10 16:51:16 -0700212 SidePropagation propagation = new SidePropagation();
213 propagation.setSide(slideEdge);
214 setPropagation(propagation);
215 }
216
George Mountecd857b2014-06-19 07:51:08 -0700217 /**
218 * Returns the edge that Views appear and disappear from.
219 *
220 * @return the edge of the scene to use for Views appearing and disappearing. One of
221 * {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
George Mount2db3bf52014-11-19 14:05:57 -0800222 * {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
223 * {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
George Mountecd857b2014-06-19 07:51:08 -0700224 * @attr ref android.R.styleable#Slide_slideEdge
225 */
George Mount7764b922016-01-13 14:51:33 -0800226 @GravityFlag
George Mountecd857b2014-06-19 07:51:08 -0700227 public int getSlideEdge() {
228 return mSlideEdge;
229 }
230
Chet Haasefaebd8f2012-05-18 14:17:57 -0700231 @Override
George Mountd6107a32014-03-10 16:51:16 -0700232 public Animator onAppear(ViewGroup sceneRoot, View view,
233 TransitionValues startValues, TransitionValues endValues) {
234 if (endValues == null) {
235 return null;
236 }
George Mount1f8c0112014-06-17 10:10:13 -0700237 int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
238 float endX = view.getTranslationX();
239 float endY = view.getTranslationY();
240 float startX = mSlideCalculator.getGoneX(sceneRoot, view);
241 float startY = mSlideCalculator.getGoneY(sceneRoot, view);
242 return TranslationAnimationCreator
243 .createAnimation(view, endValues, position[0], position[1],
George Mount727a6cf2015-06-11 15:32:14 -0700244 startX, startY, endX, endY, sDecelerate, this);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700245 }
246
George Mountd6107a32014-03-10 16:51:16 -0700247 @Override
248 public Animator onDisappear(ViewGroup sceneRoot, View view,
249 TransitionValues startValues, TransitionValues endValues) {
George Mount1f8c0112014-06-17 10:10:13 -0700250 if (startValues == null) {
251 return null;
George Mountd6107a32014-03-10 16:51:16 -0700252 }
George Mount1f8c0112014-06-17 10:10:13 -0700253 int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
254 float startX = view.getTranslationX();
255 float startY = view.getTranslationY();
256 float endX = mSlideCalculator.getGoneX(sceneRoot, view);
257 float endY = mSlideCalculator.getGoneY(sceneRoot, view);
258 return TranslationAnimationCreator
259 .createAnimation(view, startValues, position[0], position[1],
George Mount727a6cf2015-06-11 15:32:14 -0700260 startX, startY, endX, endY, sAccelerate, this);
George Mountd6107a32014-03-10 16:51:16 -0700261 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700262}