blob: 6d39ab650d28c1a24092e4da8ecce04ebbc2430d [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.view.View;
21import android.view.ViewGroup;
Chet Haase6ebe3de2013-06-17 16:50:50 -070022import android.view.ViewParent;
Chet Haasefaebd8f2012-05-18 14:17:57 -070023
24/**
25 * This transition tracks changes to the visibility of target views in the
26 * start and end scenes. Visibility is determined not just by the
27 * {@link View#setVisibility(int)} state of views, but also whether
28 * views exist in the current view hierarchy. The class is intended to be a
29 * utility for subclasses such as {@link Fade}, which use this visibility
30 * information to determine the specific animations to run when visibility
31 * changes occur. Subclasses should implement one or more of the methods
Chet Haase2ea7f8b2013-06-21 15:00:05 -070032 * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int)},
33 * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
Chet Haase6ebe3de2013-06-17 16:50:50 -070034 * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int)}, and
35 * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
Chet Haasefaebd8f2012-05-18 14:17:57 -070036 */
37public abstract class Visibility extends Transition {
38
39 private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
40 private static final String PROPNAME_PARENT = "android:visibility:parent";
41
Chet Haase6ebe3de2013-06-17 16:50:50 -070042 private static class VisibilityInfo {
43 boolean visibilityChange;
44 boolean fadeIn;
45 int startVisibility;
46 int endVisibility;
47 View startParent;
48 View endParent;
49 }
50
51 // Temporary structure, used in calculating state in setup() and play()
52 private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();
53
Chet Haasefaebd8f2012-05-18 14:17:57 -070054 @Override
55 protected void captureValues(TransitionValues values, boolean start) {
56 int visibility = values.view.getVisibility();
57 values.values.put(PROPNAME_VISIBILITY, visibility);
58 values.values.put(PROPNAME_PARENT, values.view.getParent());
59 }
60
Chet Haase6ebe3de2013-06-17 16:50:50 -070061 private boolean isHierarchyVisibilityChanging(ViewGroup sceneRoot, ViewGroup view) {
62
63 if (view == sceneRoot) {
64 return false;
65 }
66 TransitionValues startValues = getTransitionValues(view, true);
67 TransitionValues endValues = getTransitionValues(view, false);
68
69 if (startValues == null || endValues == null) {
70 return true;
71 }
72 int startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
73 View startParent = (View) startValues.values.get(PROPNAME_PARENT);
74 int endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
75 View endParent = (View) endValues.values.get(PROPNAME_PARENT);
76 if (startVisibility != endVisibility || startParent != endParent) {
77 return true;
78 }
79
80 ViewParent parent = view.getParent();
81 if (parent instanceof ViewGroup && parent != sceneRoot) {
82 return isHierarchyVisibilityChanging(sceneRoot, (ViewGroup) parent);
83 }
84 return false;
85 }
86
87 private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
Chet Haasefaebd8f2012-05-18 14:17:57 -070088 TransitionValues endValues) {
Chet Haase6ebe3de2013-06-17 16:50:50 -070089 final VisibilityInfo visInfo = mTmpVisibilityInfo;
90 visInfo.visibilityChange = false;
91 visInfo.fadeIn = false;
Chet Haasefaebd8f2012-05-18 14:17:57 -070092 if (startValues != null) {
Chet Haase6ebe3de2013-06-17 16:50:50 -070093 visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
94 visInfo.startParent = (View) startValues.values.get(PROPNAME_PARENT);
Chet Haasefaebd8f2012-05-18 14:17:57 -070095 } else {
Chet Haase6ebe3de2013-06-17 16:50:50 -070096 visInfo.startVisibility = -1;
97 visInfo.startParent = null;
Chet Haasefaebd8f2012-05-18 14:17:57 -070098 }
99 if (endValues != null) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700100 visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
101 visInfo.endParent = (View) endValues.values.get(PROPNAME_PARENT);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700102 } else {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700103 visInfo.endVisibility = -1;
104 visInfo.endParent = null;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700105 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700106 if (startValues != null && endValues != null) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700107 if (visInfo.startVisibility == visInfo.endVisibility &&
108 visInfo.startParent == visInfo.endParent) {
109 return visInfo;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700110 } else {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700111 if (visInfo.startVisibility != visInfo.endVisibility) {
112 if (visInfo.startVisibility == View.VISIBLE) {
113 visInfo.fadeIn = false;
114 visInfo.visibilityChange = true;
115 } else if (visInfo.endVisibility == View.VISIBLE) {
116 visInfo.fadeIn = true;
117 visInfo.visibilityChange = true;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700118 }
119 // no visibilityChange if going between INVISIBLE and GONE
Chet Haase6ebe3de2013-06-17 16:50:50 -0700120 } else if (visInfo.startParent != visInfo.endParent) {
121 if (visInfo.endParent == null) {
122 visInfo.fadeIn = false;
123 visInfo.visibilityChange = true;
124 } else if (visInfo.startParent == null) {
125 visInfo.fadeIn = true;
126 visInfo.visibilityChange = true;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700127 }
128 }
129 }
130 }
131 if (startValues == null) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700132 visInfo.fadeIn = true;
133 visInfo.visibilityChange = true;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700134 } else if (endValues == null) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700135 visInfo.fadeIn = false;
136 visInfo.visibilityChange = true;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700137 }
Chet Haase6ebe3de2013-06-17 16:50:50 -0700138 return visInfo;
139 }
140
141 @Override
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700142 protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
Chet Haase6ebe3de2013-06-17 16:50:50 -0700143 TransitionValues endValues) {
144 VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
145 // Ensure not in parent hierarchy that's also becoming visible/invisible
146 if (visInfo.visibilityChange) {
147 ViewGroup parent = (ViewGroup) ((visInfo.endParent != null) ?
148 visInfo.endParent : visInfo.startParent);
149 if (parent != null) {
150 if (!isHierarchyVisibilityChanging(sceneRoot, parent)) {
151 if (visInfo.fadeIn) {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700152 return appear(sceneRoot, startValues, visInfo.startVisibility,
Chet Haase6ebe3de2013-06-17 16:50:50 -0700153 endValues, visInfo.endVisibility);
154 } else {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700155 return disappear(sceneRoot, startValues, visInfo.startVisibility,
Chet Haase6ebe3de2013-06-17 16:50:50 -0700156 endValues, visInfo.endVisibility
157 );
158 }
159 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700160 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700161 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700162 return null;
163 }
164
165 /**
166 * The default implementation of this method does nothing. Subclasses
167 * should override if they need to set up anything prior to the
168 * transition starting.
169 *
170 * @param sceneRoot
Chet Haase6ebe3de2013-06-17 16:50:50 -0700171 * @param startValues
Chet Haasefaebd8f2012-05-18 14:17:57 -0700172 * @param startVisibility
Chet Haase6ebe3de2013-06-17 16:50:50 -0700173 * @param endValues
Chet Haasefaebd8f2012-05-18 14:17:57 -0700174 * @param endVisibility
175 * @return
176 */
Chet Haase6ebe3de2013-06-17 16:50:50 -0700177 protected Animator appear(ViewGroup sceneRoot,
178 TransitionValues startValues, int startVisibility,
179 TransitionValues endValues, int endVisibility) {
180 return null;
181 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700182
183 /**
184 * The default implementation of this method does nothing. Subclasses
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700185 * should override if they need to set up anything prior to the
186 * transition starting.
187 *
Chet Haasefaebd8f2012-05-18 14:17:57 -0700188 * @param sceneRoot
Chet Haase6ebe3de2013-06-17 16:50:50 -0700189 * @param startValues
Chet Haasefaebd8f2012-05-18 14:17:57 -0700190 * @param startVisibility
Chet Haase6ebe3de2013-06-17 16:50:50 -0700191 * @param endValues
Chet Haasefaebd8f2012-05-18 14:17:57 -0700192 * @param endVisibility
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700193 * @return
Chet Haasefaebd8f2012-05-18 14:17:57 -0700194 */
Chet Haase6ebe3de2013-06-17 16:50:50 -0700195 protected Animator disappear(ViewGroup sceneRoot,
196 TransitionValues startValues, int startVisibility,
197 TransitionValues endValues, int endVisibility) {
198 return null;
199 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700200
201}