diff options
| -rw-r--r-- | packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt | 23 | ||||
| -rw-r--r-- | packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt | 34 |
2 files changed, 53 insertions, 4 deletions
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt index bd3706e1aff3..00d905652987 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt @@ -70,8 +70,10 @@ class ViewHierarchyAnimator { * If a new layout change happens while an animation is already in progress, the animation * is updated to continue from the current values to the new end state. * - * A set of [excludedViews] can be passed. If any dependent view from [rootView] matches an - * entry in this set, changes to that view will not be animated. + * By default, child views whole layout changes are animated as well. However, this can be + * controlled by [animateChildren]. If children are included, a set of [excludedViews] can + * be passed. If any dependent view from [rootView] matches an entry in this set, changes to + * that view will not be animated. * * The animator continues to respond to layout changes until [stopAnimating] is called. * @@ -86,6 +88,7 @@ class ViewHierarchyAnimator { rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION, + animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ): Boolean { return animate( @@ -93,6 +96,7 @@ class ViewHierarchyAnimator { interpolator, duration, ephemeral = false, + animateChildren = animateChildren, excludedViews = excludedViews ) } @@ -106,6 +110,7 @@ class ViewHierarchyAnimator { rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION, + animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ): Boolean { return animate( @@ -113,6 +118,7 @@ class ViewHierarchyAnimator { interpolator, duration, ephemeral = true, + animateChildren = animateChildren, excludedViews = excludedViews ) } @@ -122,6 +128,7 @@ class ViewHierarchyAnimator { interpolator: Interpolator, duration: Long, ephemeral: Boolean, + animateChildren: Boolean, excludedViews: Set<View> = emptySet() ): Boolean { if ( @@ -137,7 +144,13 @@ class ViewHierarchyAnimator { } val listener = createUpdateListener(interpolator, duration, ephemeral) - addListener(rootView, listener, recursive = true, excludedViews = excludedViews) + addListener( + rootView, + listener, + recursive = true, + animateChildren = animateChildren, + excludedViews = excludedViews + ) return true } @@ -940,6 +953,7 @@ class ViewHierarchyAnimator { view: View, listener: View.OnLayoutChangeListener, recursive: Boolean = false, + animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ) { if (excludedViews.contains(view)) return @@ -952,12 +966,13 @@ class ViewHierarchyAnimator { view.addOnLayoutChangeListener(listener) view.setTag(R.id.tag_layout_listener, listener) - if (view is ViewGroup && recursive) { + if (animateChildren && view is ViewGroup && recursive) { for (i in 0 until view.childCount) { addListener( view.getChildAt(i), listener, recursive = true, + animateChildren = animateChildren, excludedViews = excludedViews ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt index 212dad78d5b2..c2e6db362035 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt @@ -242,6 +242,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test + fun animatesRootOnly() { + setUpRootWithChildren() + + val success = ViewHierarchyAnimator.animate( + rootView, + animateChildren = false + ) + // Change all bounds. + rootView.measure( + View.MeasureSpec.makeMeasureSpec(180, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY) + ) + rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */) + + assertTrue(success) + assertNotNull(rootView.getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) + // The initial values for the root view should be those of the previous layout, while the + // children views should be at the final values from the beginning. + checkBounds(rootView, l = 0, t = 0, r = 200, b = 100) + checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) + checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) + endAnimation(rootView) + assertNull(rootView.getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) + // The end values should be those of the latest layout. + checkBounds(rootView, l = 10, t = 20, r = 200, b = 120) + checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) + checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) + } + + @Test fun animatesInvisibleViews() { rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */) rootView.visibility = View.INVISIBLE |