Merge "Allow ViewHierarchyAnimator to exclude child views from animations." into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
00f62accd7
@@ -70,6 +70,9 @@ class ViewHierarchyAnimator {
|
|||||||
* If a new layout change happens while an animation is already in progress, the animation
|
* 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.
|
* 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.
|
||||||
|
*
|
||||||
* The animator continues to respond to layout changes until [stopAnimating] is called.
|
* The animator continues to respond to layout changes until [stopAnimating] is called.
|
||||||
*
|
*
|
||||||
* Successive calls to this method override the previous settings ([interpolator] and
|
* Successive calls to this method override the previous settings ([interpolator] and
|
||||||
@@ -82,9 +85,16 @@ class ViewHierarchyAnimator {
|
|||||||
fun animate(
|
fun animate(
|
||||||
rootView: View,
|
rootView: View,
|
||||||
interpolator: Interpolator = DEFAULT_INTERPOLATOR,
|
interpolator: Interpolator = DEFAULT_INTERPOLATOR,
|
||||||
duration: Long = DEFAULT_DURATION
|
duration: Long = DEFAULT_DURATION,
|
||||||
|
excludedViews: Set<View> = emptySet()
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return animate(rootView, interpolator, duration, ephemeral = false)
|
return animate(
|
||||||
|
rootView,
|
||||||
|
interpolator,
|
||||||
|
duration,
|
||||||
|
ephemeral = false,
|
||||||
|
excludedViews = excludedViews
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,16 +105,24 @@ class ViewHierarchyAnimator {
|
|||||||
fun animateNextUpdate(
|
fun animateNextUpdate(
|
||||||
rootView: View,
|
rootView: View,
|
||||||
interpolator: Interpolator = DEFAULT_INTERPOLATOR,
|
interpolator: Interpolator = DEFAULT_INTERPOLATOR,
|
||||||
duration: Long = DEFAULT_DURATION
|
duration: Long = DEFAULT_DURATION,
|
||||||
|
excludedViews: Set<View> = emptySet()
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return animate(rootView, interpolator, duration, ephemeral = true)
|
return animate(
|
||||||
|
rootView,
|
||||||
|
interpolator,
|
||||||
|
duration,
|
||||||
|
ephemeral = true,
|
||||||
|
excludedViews = excludedViews
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun animate(
|
private fun animate(
|
||||||
rootView: View,
|
rootView: View,
|
||||||
interpolator: Interpolator,
|
interpolator: Interpolator,
|
||||||
duration: Long,
|
duration: Long,
|
||||||
ephemeral: Boolean
|
ephemeral: Boolean,
|
||||||
|
excludedViews: Set<View> = emptySet()
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (
|
if (
|
||||||
!occupiesSpace(
|
!occupiesSpace(
|
||||||
@@ -119,7 +137,7 @@ class ViewHierarchyAnimator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val listener = createUpdateListener(interpolator, duration, ephemeral)
|
val listener = createUpdateListener(interpolator, duration, ephemeral)
|
||||||
addListener(rootView, listener, recursive = true)
|
addListener(rootView, listener, recursive = true, excludedViews = excludedViews)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,8 +939,11 @@ class ViewHierarchyAnimator {
|
|||||||
private fun addListener(
|
private fun addListener(
|
||||||
view: View,
|
view: View,
|
||||||
listener: View.OnLayoutChangeListener,
|
listener: View.OnLayoutChangeListener,
|
||||||
recursive: Boolean = false
|
recursive: Boolean = false,
|
||||||
|
excludedViews: Set<View> = emptySet()
|
||||||
) {
|
) {
|
||||||
|
if (excludedViews.contains(view)) return
|
||||||
|
|
||||||
// Make sure that only one listener is active at a time.
|
// Make sure that only one listener is active at a time.
|
||||||
val previousListener = view.getTag(R.id.tag_layout_listener)
|
val previousListener = view.getTag(R.id.tag_layout_listener)
|
||||||
if (previousListener != null && previousListener is View.OnLayoutChangeListener) {
|
if (previousListener != null && previousListener is View.OnLayoutChangeListener) {
|
||||||
@@ -933,7 +954,12 @@ class ViewHierarchyAnimator {
|
|||||||
view.setTag(R.id.tag_layout_listener, listener)
|
view.setTag(R.id.tag_layout_listener, listener)
|
||||||
if (view is ViewGroup && recursive) {
|
if (view is ViewGroup && recursive) {
|
||||||
for (i in 0 until view.childCount) {
|
for (i in 0 until view.childCount) {
|
||||||
addListener(view.getChildAt(i), listener, recursive = true)
|
addListener(
|
||||||
|
view.getChildAt(i),
|
||||||
|
listener,
|
||||||
|
recursive = true,
|
||||||
|
excludedViews = excludedViews
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.view.ViewGroup
|
|||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.app.animation.Interpolators
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.util.children
|
import com.android.systemui.util.children
|
||||||
import junit.framework.Assert.assertEquals
|
import junit.framework.Assert.assertEquals
|
||||||
@@ -19,7 +20,6 @@ import org.junit.After
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import com.android.app.animation.Interpolators
|
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWith(AndroidTestingRunner::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
@@ -178,7 +178,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun animatesRootAndChildren() {
|
fun animatesRootAndChildren_withoutExcludedViews() {
|
||||||
setUpRootWithChildren()
|
setUpRootWithChildren()
|
||||||
|
|
||||||
val success = ViewHierarchyAnimator.animate(rootView)
|
val success = ViewHierarchyAnimator.animate(rootView)
|
||||||
@@ -207,6 +207,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
|
|||||||
checkBounds(rootView.getChildAt(1), l = 95, t = 0, r = 190, b = 100)
|
checkBounds(rootView.getChildAt(1), l = 95, t = 0, r = 190, b = 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun animatesRootAndChildren_withExcludedViews() {
|
||||||
|
setUpRootWithChildren()
|
||||||
|
|
||||||
|
val success = ViewHierarchyAnimator.animate(
|
||||||
|
rootView,
|
||||||
|
excludedViews = setOf(rootView.getChildAt(0))
|
||||||
|
)
|
||||||
|
// 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))
|
||||||
|
assertNotNull(rootView.getChildAt(1).getTag(R.id.tag_animator))
|
||||||
|
// The initial values for the affected views should be those of the previous layout, while
|
||||||
|
// the excluded view 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 = 100, t = 0, r = 200, 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
|
@Test
|
||||||
fun animatesInvisibleViews() {
|
fun animatesInvisibleViews() {
|
||||||
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
|
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
|
||||||
|
|||||||
Reference in New Issue
Block a user