Slide.java revision 1f8c01181bcdef6e7e7e359ecde003939523b718
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
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 */
16package android.transition;
17
18import android.animation.Animator;
19import android.animation.TimeInterpolator;
20import android.view.Gravity;
21import android.view.View;
22import android.view.ViewGroup;
23import android.view.animation.AccelerateInterpolator;
24import android.view.animation.DecelerateInterpolator;
25
26/**
27 * This transition tracks changes to the visibility of target views in the
28 * start and end scenes and moves views in or out from one of the edges of the
29 * scene. Visibility is determined by both the
30 * {@link View#setVisibility(int)} state of the view as well as whether it
31 * is parented in the current view hierarchy. Disappearing Views are
32 * limited as described in {@link Visibility#onDisappear(android.view.ViewGroup,
33 * TransitionValues, int, TransitionValues, int)}.
34 */
35public class Slide extends Visibility {
36    private static final String TAG = "Slide";
37    private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
38    private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
39    private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
40    private CalculateSlide mSlideCalculator = sCalculateBottom;
41
42    private interface CalculateSlide {
43
44        /** Returns the translation value for view when it goes out of the scene */
45        float getGoneX(ViewGroup sceneRoot, View view);
46
47        /** Returns the translation value for view when it goes out of the scene */
48        float getGoneY(ViewGroup sceneRoot, View view);
49    }
50
51    private static abstract class CalculateSlideHorizontal implements CalculateSlide {
52
53        @Override
54        public float getGoneY(ViewGroup sceneRoot, View view) {
55            return view.getTranslationY();
56        }
57    }
58
59    private static abstract class CalculateSlideVertical implements CalculateSlide {
60
61        @Override
62        public float getGoneX(ViewGroup sceneRoot, View view) {
63            return view.getTranslationX();
64        }
65    }
66
67    private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
68        @Override
69        public float getGoneX(ViewGroup sceneRoot, View view) {
70            return view.getTranslationX() - sceneRoot.getWidth();
71        }
72    };
73
74    private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
75        @Override
76        public float getGoneY(ViewGroup sceneRoot, View view) {
77            return view.getTranslationY() - sceneRoot.getHeight();
78        }
79    };
80
81    private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
82        @Override
83        public float getGoneX(ViewGroup sceneRoot, View view) {
84            return view.getTranslationX() + sceneRoot.getWidth();
85        }
86    };
87
88    private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
89        @Override
90        public float getGoneY(ViewGroup sceneRoot, View view) {
91            return view.getTranslationY() + sceneRoot.getHeight();
92        }
93    };
94
95    /**
96     * Constructor using the default {@link Gravity#BOTTOM}
97     * slide edge direction.
98     */
99    public Slide() {
100        setSlideEdge(Gravity.BOTTOM);
101    }
102
103    /**
104     * Constructor using the provided slide edge direction.
105     */
106    public Slide(int slideEdge) {
107        setSlideEdge(slideEdge);
108    }
109
110    private void captureValues(TransitionValues transitionValues) {
111        View view = transitionValues.view;
112        int[] position = new int[2];
113        view.getLocationOnScreen(position);
114        transitionValues.values.put(PROPNAME_SCREEN_POSITION, position);
115    }
116
117    @Override
118    public void captureStartValues(TransitionValues transitionValues) {
119        super.captureStartValues(transitionValues);
120        captureValues(transitionValues);
121    }
122
123    @Override
124    public void captureEndValues(TransitionValues transitionValues) {
125        super.captureEndValues(transitionValues);
126        captureValues(transitionValues);
127    }
128
129    /**
130     * Change the edge that Views appear and disappear from.
131     *
132     * @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of
133     *                  {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
134     *                  {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM}.
135     */
136    public void setSlideEdge(int slideEdge) {
137        switch (slideEdge) {
138            case Gravity.LEFT:
139                mSlideCalculator = sCalculateLeft;
140                break;
141            case Gravity.TOP:
142                mSlideCalculator = sCalculateTop;
143                break;
144            case Gravity.RIGHT:
145                mSlideCalculator = sCalculateRight;
146                break;
147            case Gravity.BOTTOM:
148                mSlideCalculator = sCalculateBottom;
149                break;
150            default:
151                throw new IllegalArgumentException("Invalid slide direction");
152        }
153        SidePropagation propagation = new SidePropagation();
154        propagation.setSide(slideEdge);
155        setPropagation(propagation);
156    }
157
158    @Override
159    public Animator onAppear(ViewGroup sceneRoot, View view,
160            TransitionValues startValues, TransitionValues endValues) {
161        if (endValues == null) {
162            return null;
163        }
164        int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
165        float endX = view.getTranslationX();
166        float endY = view.getTranslationY();
167        float startX = mSlideCalculator.getGoneX(sceneRoot, view);
168        float startY = mSlideCalculator.getGoneY(sceneRoot, view);
169        return TranslationAnimationCreator
170                .createAnimation(view, endValues, position[0], position[1],
171                        startX, startY, endX, endY, sDecelerate);
172    }
173
174    @Override
175    public Animator onDisappear(ViewGroup sceneRoot, View view,
176            TransitionValues startValues, TransitionValues endValues) {
177        if (startValues == null) {
178            return null;
179        }
180        int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
181        float startX = view.getTranslationX();
182        float startY = view.getTranslationY();
183        float endX = mSlideCalculator.getGoneX(sceneRoot, view);
184        float endY = mSlideCalculator.getGoneY(sceneRoot, view);
185        return TranslationAnimationCreator
186                .createAnimation(view, startValues, position[0], position[1],
187                        startX, startY, endX, endY, sAccelerate);
188    }
189}
190