-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[LayoutAnimations] Fix exiting animations inside a Native Stack Navigator #3865
Conversation
b594651
to
109ded6
Compare
if (indicesToRemove != null) { | ||
for (int index : indicesToRemove) { | ||
View child = viewGroupManager.getChildAt(viewGroup, index); | ||
((ReaLayoutAnimator) mReaLayoutAnimator).cancelAnimationsInSubviews(child); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix for Android is to cancel all the animations in the transaction that removes the Screen.
This will cause all the exiting views to unregister their ancestors before being unmounted.
android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java
Show resolved
Hide resolved
NSNumber *parentTag = _exitingParentTags[child.reactTag]; | ||
[_exitingParentTags removeObjectForKey:child.reactTag]; | ||
while (parentTag != nil && ![parent isKindOfClass:[RCTRootView class]]) { | ||
UIView *view = parent; | ||
NSNumber *viewTag = parentTag; | ||
parentTag = _exitingParentTags[viewTag]; | ||
UIView *viewByTag = [self viewForTag:viewTag]; | ||
parent = view.superview; | ||
|
||
if (view == nil) { | ||
if (viewByTag == nil) { | ||
// the view was already removed from both native and RN hierarchies | ||
// we can safely forget that it had any animated children | ||
[_ancestorsToRemove removeObject:viewTag]; | ||
[_exitingSubviewsCountMap removeObjectForKey:viewTag]; | ||
[_exitingParentTags removeObjectForKey:viewTag]; | ||
continue; | ||
} | ||
// the child was dettached from view, but view is still | ||
// in the native and RN hierarchy | ||
view = viewByTag; | ||
} | ||
|
||
if (view.reactTag == nil) { | ||
// we skip over views with no tag when registering parent tags, | ||
// so we shouldn't go to the parent of viewTag yet | ||
parentTag = viewTag; | ||
continue; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On iOS, we can't simply cancel animations in the removed screen like on Android, since by the time manageChildren
is called on the removed screen, it's already been removed from the native hierarchy.
Instead, when unregistering ancestors when the animations end, we use the tags of ancestors instead of view.superview
refs to find the parents of the exiting views.
I think this approach is ok. I'm only wondering if the changes that check for RNScreen are necessary for this to work. If I understand this correctly, it seem like these are separate things, and the changes that reference screens are there to prevent exiting views from animating when the whole screen is unmounted. If that's the case I think it'd be better to split these changes into separate PRs. Also blocking exiting animations in such a case may be in conflict with the work we do on SET (cc @piaskowyk ) |
On iOS, cancelling animations in subviews of a |
416db71
to
3c4d0a6
Compare
…_native_stack_fix
...ager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java
Outdated
Show resolved
Hide resolved
android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java
Show resolved
Hide resolved
android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java
Show resolved
Hide resolved
Could you also resolve merge conflicts? |
Could you also check how it works on native stack and js stack? |
cb6042a
to
e985442
Compare
It does, though this shouldn't really change the behaviour with js stack. |
...ager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java
Outdated
Show resolved
Hide resolved
android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java
Show resolved
Hide resolved
This is the last iteration and then we could merge it |
…ator (software-mansion#3865) <!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please follow the template so that the reviewers can easily understand what the code changes affect. --> ## Summary Currently, removing a screen with `exiting` layout animations running cause views to not be properly removed from the native hierarchy, as well as leaking memory in Layout Animations' `AnimationManager`. This is caused by the ancestors of exiting views being removed from the native hierarchy by the React-Native-Screens implementation, while our implementation assumes they're still mounted in the native hierarchy. ## Test plan <!-- Provide a minimal but complete code snippet that can be used to test out this change along with instructions how to run it and a description of the expected behavior. --> In the Example app, go to the "Nested NativeStacks with layout" screen and try toggling and navigating around while the `exiting` animation on the second screen of the nested stack is running.
Summary
Currently, removing a screen with
exiting
layout animations running cause views to not be properly removed from the native hierarchy, as well as leaking memory in Layout Animations'AnimationManager
.This is caused by the ancestors of exiting views being removed from the native hierarchy by the React-Native-Screens implementation, while our implementation assumes they're still mounted in the native hierarchy.
Test plan
In the Example app, go to the "Nested NativeStacks with layout" screen and try toggling and navigating around while the
exiting
animation on the second screen of the nested stack is running.