From 42e09bc8e3ff4e5bfd3066e163908df32e7f5d38 Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Mon, 31 Aug 2026 03:12:54 +0300 Subject: [PATCH] Fixed cancelling running stack animations --- .../viewcontrollers/stack/StackAnimator.kt | 6 +++- .../stack/StackAnimatorTest.kt | 28 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimator.kt b/android/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimator.kt index 59e82531b2d..ab6b2873b5f 100644 --- a/android/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimator.kt +++ b/android/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimator.kt @@ -34,7 +34,7 @@ open class StackAnimator @JvmOverloads constructor( @VisibleForTesting val runningSetRootAnimations: MutableMap, AnimatorSet> = HashMap() - fun cancelPushAnimations() = runningPushAnimations.values.forEach(Animator::cancel) + fun cancelPushAnimations() = runningPushAnimations.values.toList().forEach(Animator::cancel) open fun isChildInTransition(child: ViewController<*>?): Boolean { return runningPushAnimations.containsKey(child) || @@ -43,9 +43,13 @@ open class StackAnimator @JvmOverloads constructor( } fun cancelAllAnimations() { + val animations = runningPushAnimations.values + + runningPopAnimations.values + + runningSetRootAnimations.values runningPushAnimations.clear() runningPopAnimations.clear() runningSetRootAnimations.clear() + animations.forEach(Animator::cancel) } fun setRoot( diff --git a/android/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt b/android/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt index 581fbe44006..9f4947fc167 100644 --- a/android/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt +++ b/android/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt @@ -213,6 +213,32 @@ class StackAnimatorTest : BaseTest() { assertThat(uut.isChildInTransition(child3)).isTrue() } + @Test + fun cancelAllAnimations_cancelsRunningAnimatorsWithoutCompletingCommands() { + val onAnimationEnd = mock() + uut.push(child2, child1, Options.EMPTY, emptyList(), onAnimationEnd) + + uut.cancelAllAnimations() + + verify(commandAnimator).cancel() + verify(onAnimationEnd, never()).run() + assertThat(uut.isChildInTransition(child2)).isFalse() + } + + @Test + fun cancelPushAnimations_cancelsEveryRunningAnimator() { + uut.push(child2, child1, Options.EMPTY, emptyList(), mock()) + val firstAnimator = uut.runningPushAnimations[child2]!! + val child3 = SimpleViewController(activity, mock(), "child3", Options()) + uut.push(child3, child2, Options.EMPTY, emptyList(), mock()) + val secondAnimator = uut.runningPushAnimations[child3]!! + + uut.cancelPushAnimations() + + verify(firstAnimator).cancel() + verify(secondAnimator).cancel() + } + private fun mockViewController(): ViewController<*> { val vc = mock>() val view = FrameLayout(activity) @@ -240,4 +266,4 @@ class StackAnimatorTest : BaseTest() { vc.mergeOptions(this) } } -} \ No newline at end of file +}