Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 1 | /* |
| 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 Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 16 | |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 17 | package android.view.transition; |
| 18 | |
| 19 | import android.animation.Animator; |
| 20 | import android.view.View; |
| 21 | import android.view.ViewGroup; |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 22 | import android.view.ViewParent; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 23 | |
| 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 Haase | 2ea7f8b | 2013-06-21 15:00:05 -0700 | [diff] [blame] | 32 | * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int)}, |
| 33 | * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)}, |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 34 | * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int)}, and |
| 35 | * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)}. |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 36 | */ |
| 37 | public 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 Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 42 | 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 Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 54 | @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 Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 61 | 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 Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 88 | TransitionValues endValues) { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 89 | final VisibilityInfo visInfo = mTmpVisibilityInfo; |
| 90 | visInfo.visibilityChange = false; |
| 91 | visInfo.fadeIn = false; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 92 | if (startValues != null) { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 93 | visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY); |
| 94 | visInfo.startParent = (View) startValues.values.get(PROPNAME_PARENT); |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 95 | } else { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 96 | visInfo.startVisibility = -1; |
| 97 | visInfo.startParent = null; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 98 | } |
| 99 | if (endValues != null) { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 100 | visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY); |
| 101 | visInfo.endParent = (View) endValues.values.get(PROPNAME_PARENT); |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 102 | } else { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 103 | visInfo.endVisibility = -1; |
| 104 | visInfo.endParent = null; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 105 | } |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 106 | if (startValues != null && endValues != null) { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 107 | if (visInfo.startVisibility == visInfo.endVisibility && |
| 108 | visInfo.startParent == visInfo.endParent) { |
| 109 | return visInfo; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 110 | } else { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 111 | 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 Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 118 | } |
| 119 | // no visibilityChange if going between INVISIBLE and GONE |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 120 | } 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 Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 127 | } |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | if (startValues == null) { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 132 | visInfo.fadeIn = true; |
| 133 | visInfo.visibilityChange = true; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 134 | } else if (endValues == null) { |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 135 | visInfo.fadeIn = false; |
| 136 | visInfo.visibilityChange = true; |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 137 | } |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 138 | return visInfo; |
| 139 | } |
| 140 | |
| 141 | @Override |
Chet Haase | 2ea7f8b | 2013-06-21 15:00:05 -0700 | [diff] [blame] | 142 | protected Animator play(ViewGroup sceneRoot, TransitionValues startValues, |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 143 | 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 Haase | 2ea7f8b | 2013-06-21 15:00:05 -0700 | [diff] [blame] | 152 | return appear(sceneRoot, startValues, visInfo.startVisibility, |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 153 | endValues, visInfo.endVisibility); |
| 154 | } else { |
Chet Haase | 2ea7f8b | 2013-06-21 15:00:05 -0700 | [diff] [blame] | 155 | return disappear(sceneRoot, startValues, visInfo.startVisibility, |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 156 | endValues, visInfo.endVisibility |
| 157 | ); |
| 158 | } |
| 159 | } |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 160 | } |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 161 | } |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 162 | 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 Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 171 | * @param startValues |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 172 | * @param startVisibility |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 173 | * @param endValues |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 174 | * @param endVisibility |
| 175 | * @return |
| 176 | */ |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 177 | protected Animator appear(ViewGroup sceneRoot, |
| 178 | TransitionValues startValues, int startVisibility, |
| 179 | TransitionValues endValues, int endVisibility) { |
| 180 | return null; |
| 181 | } |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 182 | |
| 183 | /** |
| 184 | * The default implementation of this method does nothing. Subclasses |
Chet Haase | 2ea7f8b | 2013-06-21 15:00:05 -0700 | [diff] [blame] | 185 | * should override if they need to set up anything prior to the |
| 186 | * transition starting. |
| 187 | * |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 188 | * @param sceneRoot |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 189 | * @param startValues |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 190 | * @param startVisibility |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 191 | * @param endValues |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 192 | * @param endVisibility |
Chet Haase | 2ea7f8b | 2013-06-21 15:00:05 -0700 | [diff] [blame] | 193 | * @return |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 194 | */ |
Chet Haase | 6ebe3de | 2013-06-17 16:50:50 -0700 | [diff] [blame] | 195 | protected Animator disappear(ViewGroup sceneRoot, |
| 196 | TransitionValues startValues, int startVisibility, |
| 197 | TransitionValues endValues, int endVisibility) { |
| 198 | return null; |
| 199 | } |
Chet Haase | faebd8f | 2012-05-18 14:17:57 -0700 | [diff] [blame] | 200 | |
| 201 | } |