blob: 4fd60c14f47ecb04407fa8ddac093fdd9cc1a13b [file] [log] [blame]
Chet Haasefaebd8f2012-05-18 14:17:57 -07001/*
2 * Copyright (C) 2013 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 */
Chet Haase6ebe3de2013-06-17 16:50:50 -070016
Chet Haasefaebd8f2012-05-18 14:17:57 -070017package android.view.transition;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
22import android.util.Log;
23import android.view.View;
24import android.view.ViewGroup;
25
26/**
27 * This transition tracks changes to the visibility of target views in the
28 * start and end scenes and fades views in or out when they become visible
29 * or non-visible. 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.
32 */
33public class Fade extends Visibility {
34
Chet Haasec43524f2013-07-16 14:40:11 -070035 private static boolean DBG = Transition.DBG && false;
36
Chet Haasefaebd8f2012-05-18 14:17:57 -070037 private static final String LOG_TAG = "Fade";
Chet Haase6ebe3de2013-06-17 16:50:50 -070038 private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
39 private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
Chet Haasefaebd8f2012-05-18 14:17:57 -070040
41 /**
42 * Fading mode used in {@link #Fade(int)} to make the transition
43 * operate on targets that are appearing. Maybe be combined with
44 * {@link #OUT} to fade both in and out.
45 */
46 public static final int IN = 0x1;
47 /**
48 * Fading mode used in {@link #Fade(int)} to make the transition
49 * operate on targets that are disappearing. Maybe be combined with
50 * {@link #IN} to fade both in and out.
51 */
52 public static final int OUT = 0x2;
53
54 private int mFadingMode;
55
56 /**
57 * Constructs a Fade transition that will fade targets in and out.
58 */
59 public Fade() {
60 this(IN | OUT);
61 }
62
63 /**
64 * Constructs a Fade transition that will fade targets in
65 * and/or out, according to the value of fadingMode.
66 *
67 * @param fadingMode The behavior of this transition, a combination of
68 * {@link #IN} and {@link #OUT}.
69 */
70 public Fade(int fadingMode) {
71 mFadingMode = fadingMode;
72 }
73
74 /**
75 * Utility method to handle creating and running the Animator.
76 */
77 private Animator runAnimation(View view, float startAlpha, float endAlpha,
78 Animator.AnimatorListener listener) {
79 final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
80 if (listener != null) {
81 anim.addListener(listener);
82 }
83 // TODO: Maybe extract a method into Transition to run an animation that handles the
84 // duration/startDelay stuff for all subclasses.
85 return anim;
86 }
87
88 @Override
Chet Haase6ebe3de2013-06-17 16:50:50 -070089 protected void captureValues(TransitionValues values, boolean start) {
90 super.captureValues(values, start);
91 int[] loc = new int[2];
92 values.view.getLocationOnScreen(loc);
93 values.values.put(PROPNAME_SCREEN_X, loc[0]);
94 values.values.put(PROPNAME_SCREEN_Y, loc[1]);
95 }
96
97 @Override
Chet Haase6ebe3de2013-06-17 16:50:50 -070098 protected Animator appear(ViewGroup sceneRoot,
99 TransitionValues startValues, int startVisibility,
100 TransitionValues endValues, int endVisibility) {
Chet Haasedc57d9d2013-07-10 11:27:54 -0700101 if ((mFadingMode & IN) != IN || endValues == null) {
Chet Haasefaebd8f2012-05-18 14:17:57 -0700102 return null;
103 }
Chet Haasedc57d9d2013-07-10 11:27:54 -0700104 final View endView = endValues.view;
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700105 endView.setAlpha(0);
Chet Haasedc57d9d2013-07-10 11:27:54 -0700106 final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
107 @Override
108 public void onAnimationEnd(Animator animation) {
109 // Always end animation with full alpha, in case it's canceled mid-stream
110 endView.setAlpha(1);
111 }
112 };
113 return runAnimation(endView, 0, 1, endListener);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700114 }
115
116 @Override
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700117 protected Animator disappear(ViewGroup sceneRoot,
Chet Haase6ebe3de2013-06-17 16:50:50 -0700118 TransitionValues startValues, int startVisibility,
119 TransitionValues endValues, int endVisibility) {
Chet Haasefaebd8f2012-05-18 14:17:57 -0700120 if ((mFadingMode & OUT) != OUT) {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700121 return null;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700122 }
Chet Haase6ebe3de2013-06-17 16:50:50 -0700123 View view;
124 View startView = (startValues != null) ? startValues.view : null;
125 View endView = (endValues != null) ? endValues.view : null;
Chet Haasec43524f2013-07-16 14:40:11 -0700126 if (DBG) {
Chet Haasefaebd8f2012-05-18 14:17:57 -0700127 Log.d(LOG_TAG, "Fade.predisappear: startView, startVis, endView, endVis = " +
128 startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
129 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700130 View overlayView = null;
131 View viewToKeep = null;
132 if (endView == null) {
133 // view was removed: add the start view to the Overlay
134 view = startView;
135 overlayView = view;
136 } else {
137 // visibility change
138 if (endVisibility == View.INVISIBLE) {
139 view = endView;
140 viewToKeep = view;
141 } else {
142 // Becoming GONE
143 if (startView == endView) {
144 view = endView;
145 viewToKeep = view;
146 } else {
147 view = startView;
148 overlayView = view;
149 }
150 }
151 }
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700152 final int finalVisibility = endVisibility;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700153 // TODO: add automatic facility to Visibility superclass for keeping views around
154 if (overlayView != null) {
155 // TODO: Need to do this for general case of adding to overlay
Chet Haase6ebe3de2013-06-17 16:50:50 -0700156 int screenX = (Integer) startValues.values.get(PROPNAME_SCREEN_X);
157 int screenY = (Integer) startValues.values.get(PROPNAME_SCREEN_Y);
158 int[] loc = new int[2];
159 sceneRoot.getLocationOnScreen(loc);
160 overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
161 overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
Chet Haasefaebd8f2012-05-18 14:17:57 -0700162 sceneRoot.getOverlay().add(overlayView);
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700163 // TODO: add automatic facility to Visibility superclass for keeping views around
164 final float startAlpha = view.getAlpha();
165 float endAlpha = 0;
166 final View finalView = view;
167 final View finalOverlayView = overlayView;
168 final View finalViewToKeep = viewToKeep;
169 final ViewGroup finalSceneRoot = sceneRoot;
170 final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
171 @Override
172 public void onAnimationEnd(Animator animation) {
173 finalView.setAlpha(startAlpha);
174 // TODO: restore view offset from overlay repositioning
175 if (finalViewToKeep != null) {
176 finalViewToKeep.setVisibility(finalVisibility);
177 }
178 if (finalOverlayView != null) {
179 finalSceneRoot.getOverlay().remove(finalOverlayView);
180 }
181 }
182 };
183 return runAnimation(view, startAlpha, endAlpha, endListener);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700184 }
185 if (viewToKeep != null) {
186 // TODO: find a different way to do this, like just changing the view to be
187 // VISIBLE for the duration of the transition
188 viewToKeep.setVisibility((View.VISIBLE));
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700189 // TODO: add automatic facility to Visibility superclass for keeping views around
190 final float startAlpha = view.getAlpha();
191 float endAlpha = 0;
192 final View finalView = view;
193 final View finalOverlayView = overlayView;
194 final View finalViewToKeep = viewToKeep;
195 final ViewGroup finalSceneRoot = sceneRoot;
196 final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
197 @Override
198 public void onAnimationEnd(Animator animation) {
199 finalView.setAlpha(startAlpha);
200 // TODO: restore view offset from overlay repositioning
201 if (finalViewToKeep != null) {
202 finalViewToKeep.setVisibility(finalVisibility);
203 }
204 if (finalOverlayView != null) {
205 finalSceneRoot.getOverlay().remove(finalOverlayView);
206 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700207 }
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700208 };
209 return runAnimation(view, startAlpha, endAlpha, endListener);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700210 }
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700211 return null;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700212 }
213
214}