summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
authorChet Haase <chet@google.com>2015-04-07 10:29:39 -0700
committerChet Haase <chet@google.com>2015-04-17 00:30:21 +0000
commitc633d2f2b88e74c155af20164984cb6a02dafffe (patch)
tree9265cff3617961e28986c7d9d4af14cd7dab2c42 /core/java/android
parent71a9cfc08cbf20ba29b84b8a3a89a3db30ff089e (diff)
downloadframeworks_base-c633d2f2b88e74c155af20164984cb6a02dafffe.zip
frameworks_base-c633d2f2b88e74c155af20164984cb6a02dafffe.tar.gz
frameworks_base-c633d2f2b88e74c155af20164984cb6a02dafffe.tar.bz2
Add transient views to ViewGroup
This change allows clients to add temporary (transient) views to a list of such views in any layout container. These views will be drawn at the specified index when the container is being rendered, but will otherwise not participate in the normal events of child views, such as focus, input, and accessibility. The purpose of this functionality is to enable better animations when views have been removed, such that clients can add them back into containers temporarily while an animation runs, then remove them when the animation finishes. This functionality is similar, albeit a subset, of the what ViewGroupOverlay provides, but this API allows clients to interleave these views with the other children in the container, which allows correct drawing order. ViewGroupOverlay, and the older internal mechanism used by the old animation package, draw all of their views after a container is drawn, which pops these temporary views on top of the other children in the container. Issue #18621099 Enable View overlay to respect elevation and shadows Change-Id: I530df69b406aa27b9f551f5724384f4dd1215a6f
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/view/ViewGroup.java187
1 files changed, 187 insertions, 0 deletions
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 10724b0..afc0eee 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -494,6 +494,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
private int mNestedScrollAxes;
+ // Used to manage the list of transient views, added by addTransientView()
+ private List<Integer> mTransientIndices = null;
+ private List<View> mTransientViews = null;
+
+
/**
* Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
*
@@ -2822,6 +2827,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
child.dispatchAttachedToWindow(info,
visibility | (child.mViewFlags & VISIBILITY_MASK));
}
+ final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ View view = mTransientViews.get(i);
+ view.dispatchAttachedToWindow(info, visibility | (view.mViewFlags & VISIBILITY_MASK));
+ }
}
@Override
@@ -2991,6 +3001,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
children[i].dispatchDetachedFromWindow();
}
clearDisappearingChildren();
+ final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ View view = mTransientViews.get(i);
+ view.dispatchDetachedFromWindow();
+ }
super.dispatchDetachedFromWindow();
}
@@ -3291,6 +3306,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final long drawingTime = getDrawingTime();
if (usingRenderNodeProperties) canvas.insertReorderBarrier();
+ final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
+ int transientIndex = transientCount != 0 ? 0 : -1;
// Only use the preordered list if not HW accelerated, since the HW pipeline will do the
// draw reordering internally
final ArrayList<View> preorderedList = usingRenderNodeProperties
@@ -3298,6 +3315,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
for (int i = 0; i < childrenCount; i++) {
+ while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
+ final View transientChild = mTransientViews.get(transientIndex);
+ if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
+ transientChild.getAnimation() != null) {
+ more |= drawChild(canvas, transientChild, drawingTime);
+ }
+ transientIndex++;
+ if (transientIndex >= transientCount) {
+ transientIndex = -1;
+ }
+ }
int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null)
? children[childIndex] : preorderedList.get(childIndex);
@@ -3305,6 +3333,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
more |= drawChild(canvas, child, drawingTime);
}
}
+ while (transientIndex >= 0) {
+ // there may be additional transient views after the normal views
+ final View transientChild = mTransientViews.get(transientIndex);
+ if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
+ transientChild.getAnimation() != null) {
+ more |= drawChild(canvas, transientChild, drawingTime);
+ }
+ transientIndex++;
+ if (transientIndex >= transientCount) {
+ break;
+ }
+ }
if (preorderedList != null) preorderedList.clear();
// Draw any disappearing views that have animations
@@ -3785,6 +3825,135 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
+ * This method adds a view to this container at the specified index purely for the
+ * purposes of allowing that view to draw even though it is not a normal child of
+ * the container. That is, the view does not participate in layout, focus, accessibility,
+ * input, or other normal view operations; it is purely an item to be drawn during the normal
+ * rendering operation of this container. The index that it is added at is the order
+ * in which it will be drawn, with respect to the other views in the container.
+ * For example, a transient view added at index 0 will be drawn before all other views
+ * in the container because it will be drawn first (including before any real view
+ * at index 0). There can be more than one transient view at any particular index;
+ * these views will be drawn in the order in which they were added to the list of
+ * transient views. The index of transient views can also be greater than the number
+ * of normal views in the container; that just means that they will be drawn after all
+ * other views are drawn.
+ *
+ * <p>Note that since transient views do not participate in layout, they must be sized
+ * manually or, more typically, they should just use the size that they had before they
+ * were removed from their container.</p>
+ *
+ * <p>Transient views are useful for handling animations of views that have been removed
+ * from the container, but which should be animated out after the removal. Adding these
+ * views as transient views allows them to participate in drawing without side-effecting
+ * the layout of the container.</p>
+ *
+ * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
+ * from the container when they are no longer needed. For example, a transient view
+ * which is added in order to fade it out in its old location should be removed
+ * once the animation is complete.</p>
+ *
+ * @param view The view to be added
+ * @param index The index at which this view should be drawn, must be >= 0.
+ * This value is relative to the {@link #getChildAt(int) index} values in the normal
+ * child list of this container, where any transient view at a particular index will
+ * be drawn before any normal child at that same index.
+ */
+ public void addTransientView(View view, int index) {
+ if (index < 0) {
+ return;
+ }
+ if (mTransientIndices == null) {
+ mTransientIndices = new ArrayList<Integer>();
+ mTransientViews = new ArrayList<View>();
+ }
+ final int oldSize = mTransientIndices.size();
+ if (oldSize > 0) {
+ int insertionIndex;
+ for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
+ if (index < mTransientIndices.get(insertionIndex)) {
+ break;
+ }
+ }
+ mTransientIndices.add(insertionIndex, index);
+ mTransientViews.add(insertionIndex, view);
+ } else {
+ mTransientIndices.add(index);
+ mTransientViews.add(view);
+ }
+ view.mParent = this;
+ view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
+ invalidate(true);
+ }
+
+ /**
+ * Removes a view from the list of transient views in this container. If there is no
+ * such transient view, this method does nothing.
+ *
+ * @param view The transient view to be removed
+ */
+ public void removeTransientView(View view) {
+ if (mTransientViews == null) {
+ return;
+ }
+ final int size = mTransientViews.size();
+ for (int i = 0; i < size; ++i) {
+ if (view == mTransientViews.get(i)) {
+ mTransientViews.remove(i);
+ mTransientIndices.remove(i);
+ view.mParent = null;
+ view.dispatchDetachedFromWindow();
+ invalidate(true);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Returns the number of transient views in this container. Specific transient
+ * views and the index at which they were added can be retrieved via
+ * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
+ *
+ * @see #addTransientView(View, int)
+ * @return The number of transient views in this container
+ */
+ public int getTransientViewCount() {
+ return mTransientIndices == null ? 0 : mTransientIndices.size();
+ }
+
+ /**
+ * Given a valid position within the list of transient views, returns the index of
+ * the transient view at that position.
+ *
+ * @param position The position of the index being queried. Must be at least 0
+ * and less than the value returned by {@link #getTransientViewCount()}.
+ * @return The index of the transient view stored in the given position if the
+ * position is valid, otherwise -1
+ */
+ public int getTransientViewIndex(int position) {
+ if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
+ return -1;
+ }
+ return mTransientIndices.get(position);
+ }
+
+ /**
+ * Given a valid position within the list of transient views, returns the
+ * transient view at that position.
+ *
+ * @param position The position of the view being queried. Must be at least 0
+ * and less than the value returned by {@link #getTransientViewCount()}.
+ * @return The transient view stored in the given position if the
+ * position is valid, otherwise null
+ */
+ public View getTransientView(int position) {
+ if (mTransientViews == null || position >= mTransientViews.size()) {
+ return null;
+ }
+ return mTransientViews.get(position);
+ }
+
+ /**
* <p>Adds a child view. If no layout parameters are already set on the child, the
* default parameters for this ViewGroup are set on the child.</p>
*
@@ -4096,6 +4265,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (child.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
+
+ if (mTransientIndices != null) {
+ final int transientCount = mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ final int oldIndex = mTransientIndices.get(i);
+ if (index <= oldIndex) {
+ mTransientIndices.set(i, oldIndex + 1);
+ }
+ }
+ }
}
private void addInArray(View child, int index) {
@@ -4340,6 +4519,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (view.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
+
+ int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ final int oldIndex = mTransientIndices.get(i);
+ if (index < oldIndex) {
+ mTransientIndices.set(i, oldIndex - 1);
+ }
+ }
}
/**