From a97dd6e4c183233a94a52624d63eecfe663a56a2 Mon Sep 17 00:00:00 2001 From: gulevsky Date: Fri, 25 Oct 2024 17:19:52 +0300 Subject: [PATCH] cancel transitions when scene root has detached commit_hash:db2fa3bb7d4d0861d219cb6b8978d9ad61bf8391 --- .mapping.json | 1 + CHANGELOG.md | 1 + .../div/core/state/DivStateChangeListener.kt | 2 ++ .../com/yandex/div/core/view2/Div2View.kt | 4 ++- .../core/view2/animations/SceneRootWatcher.kt | 33 +++++++++++++++++++ .../div/core/view2/divs/DivStateBinder.kt | 2 ++ 6 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 client/android/div/src/main/java/com/yandex/div/core/view2/animations/SceneRootWatcher.kt diff --git a/.mapping.json b/.mapping.json index 949956d0e..8091f9160 100644 --- a/.mapping.json +++ b/.mapping.json @@ -1210,6 +1210,7 @@ "client/android/div/src/main/java/com/yandex/div/core/view2/animations/Fade.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/Fade.kt", "client/android/div/src/main/java/com/yandex/div/core/view2/animations/OutlineAwareVisibility.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/OutlineAwareVisibility.kt", "client/android/div/src/main/java/com/yandex/div/core/view2/animations/Scale.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/Scale.kt", + "client/android/div/src/main/java/com/yandex/div/core/view2/animations/SceneRootWatcher.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/SceneRootWatcher.kt", "client/android/div/src/main/java/com/yandex/div/core/view2/animations/Slide.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/Slide.kt", "client/android/div/src/main/java/com/yandex/div/core/view2/animations/Transitions.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/Transitions.kt", "client/android/div/src/main/java/com/yandex/div/core/view2/animations/Utils.kt":"divkit/public/client/android/div/src/main/java/com/yandex/div/core/view2/animations/Utils.kt", diff --git a/CHANGELOG.md b/CHANGELOG.md index 90e49cc18..123e8f42f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ # Android Client: * Added API to force specific `Div2View` to use canvas clipping. * Fixed optional expression resolving when default value is defined. +* Fixed running transition behavior when scene root is detached. # iOS Client: * Add `isEmpty()` method to dict and array. diff --git a/client/android/div/src/main/java/com/yandex/div/core/state/DivStateChangeListener.kt b/client/android/div/src/main/java/com/yandex/div/core/state/DivStateChangeListener.kt index 694bfcc82..f1341fa5e 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/state/DivStateChangeListener.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/state/DivStateChangeListener.kt @@ -6,6 +6,7 @@ import androidx.transition.TransitionManager import com.yandex.div.core.animation.SpringInterpolator import com.yandex.div.core.annotations.PublicApi import com.yandex.div.core.view2.Div2View +import com.yandex.div.core.view2.animations.SceneRootWatcher import javax.inject.Provider @PublicApi @@ -37,6 +38,7 @@ class DefaultDivStateChangeListener @JvmOverloads constructor( val rootView = rootViewProvider.get() ?: return val transition = DivStateTransition(divView).setInterpolator(interpolator) TransitionManager.endTransitions(rootView) + SceneRootWatcher.watchFor(rootView, transition) TransitionManager.beginDelayedTransition(rootView, transition) } } diff --git a/client/android/div/src/main/java/com/yandex/div/core/view2/Div2View.kt b/client/android/div/src/main/java/com/yandex/div/core/view2/Div2View.kt index 6ee741b6f..128a5afc4 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/view2/Div2View.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/view2/Div2View.kt @@ -45,6 +45,7 @@ import com.yandex.div.core.util.SingleTimeOnAttachCallback import com.yandex.div.core.util.walk import com.yandex.div.core.view2.animations.DivComparator import com.yandex.div.core.view2.animations.DivTransitionHandler +import com.yandex.div.core.view2.animations.SceneRootWatcher import com.yandex.div.core.view2.animations.allowsTransitionsOnDataChange import com.yandex.div.core.view2.animations.doOnEnd import com.yandex.div.core.view2.divs.DivLayoutProviderVariablesHolder @@ -877,8 +878,9 @@ class Div2View private constructor( } if (transition != null) { - val newStateScene = Scene(this, newStateView) TransitionManager.endTransitions(this) + val newStateScene = Scene(this, newStateView) + SceneRootWatcher.watchFor(newStateScene, transition) TransitionManager.go(newStateScene, transition) } else { addView(newStateView) diff --git a/client/android/div/src/main/java/com/yandex/div/core/view2/animations/SceneRootWatcher.kt b/client/android/div/src/main/java/com/yandex/div/core/view2/animations/SceneRootWatcher.kt new file mode 100644 index 000000000..60cffd9dd --- /dev/null +++ b/client/android/div/src/main/java/com/yandex/div/core/view2/animations/SceneRootWatcher.kt @@ -0,0 +1,33 @@ +package com.yandex.div.core.view2.animations + +import android.view.View +import android.view.View.OnAttachStateChangeListener +import android.view.ViewGroup +import androidx.transition.Scene +import androidx.transition.Transition +import androidx.transition.TransitionManager + +internal object SceneRootWatcher { + + fun watchFor(scene: Scene, transition: Transition) { + watchFor(scene.sceneRoot, transition) + } + + fun watchFor(sceneRoot: ViewGroup, transition: Transition) { + val detachListener = OnDetachListener(sceneRoot) + sceneRoot.addOnAttachStateChangeListener(detachListener) + transition.doOnEnd { sceneRoot.removeOnAttachStateChangeListener(detachListener) } + } + + private class OnDetachListener( + private val sceneRoot: ViewGroup + ) : OnAttachStateChangeListener { + + override fun onViewAttachedToWindow(view: View) = Unit + + override fun onViewDetachedFromWindow(view: View) { + sceneRoot.removeOnAttachStateChangeListener(this) + TransitionManager.endTransitions(sceneRoot) + } + } +} diff --git a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivStateBinder.kt b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivStateBinder.kt index 3ac312ac7..2de68aac0 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivStateBinder.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivStateBinder.kt @@ -32,6 +32,7 @@ import com.yandex.div.core.view2.DivVisibilityActionTracker import com.yandex.div.core.view2.animations.DivComparator import com.yandex.div.core.view2.animations.Fade import com.yandex.div.core.view2.animations.Scale +import com.yandex.div.core.view2.animations.SceneRootWatcher import com.yandex.div.core.view2.animations.VerticalTranslation import com.yandex.div.core.view2.animations.allowsTransitionsOnStateChange import com.yandex.div.core.view2.divs.widgets.DivStateLayout @@ -132,6 +133,7 @@ internal class DivStateBinder @Inject constructor( if (transition != null) { TransitionManager.endTransitions(layout) + SceneRootWatcher.watchFor(layout, transition) TransitionManager.beginDelayedTransition(layout, transition) } layout.releaseAndRemoveChildren(divView)