Skip to content

Commit dedf937

Browse files
Luna Weifacebook-github-bot
authored andcommitted
Track animations and flush them
Summary: Changelog: [Internal] Track delete animations and when `manageChildren` is called on a certain view tag, finish all pending deletion animations before manipulating children Reviewed By: JoshuaGross Differential Revision: D20319824 fbshipit-source-id: b594d0e6e9b6fecc5eca2938f284be631494e55c
1 parent d3b93f7 commit dedf937

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ public synchronized void manageChildren(
363363
@Nullable int[] tagsToDelete) {
364364
UiThreadUtil.assertOnUiThread();
365365

366+
mLayoutAnimator.cancelAnimationsForViewTag(tag);
367+
366368
final ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag);
367369
final ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(tag);
368370
if (viewToManage == null) {
@@ -445,6 +447,7 @@ && arrayContains(tagsToDelete, viewToRemove.getId())) {
445447

446448
if (mLayoutAnimationEnabled && mLayoutAnimator.shouldAnimateLayout(viewToDestroy)) {
447449
mLayoutAnimator.deleteView(
450+
tag,
448451
viewToDestroy,
449452
new LayoutAnimationListener() {
450453
@Override

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.facebook.react.bridge.Callback;
1818
import com.facebook.react.bridge.ReadableMap;
1919
import com.facebook.react.bridge.UiThreadUtil;
20+
import java.util.ArrayList;
2021
import javax.annotation.concurrent.NotThreadSafe;
2122

2223
/**
@@ -31,6 +32,8 @@ public class LayoutAnimationController {
3132
private final AbstractLayoutAnimation mLayoutUpdateAnimation = new LayoutUpdateAnimation();
3233
private final AbstractLayoutAnimation mLayoutDeleteAnimation = new LayoutDeleteAnimation();
3334
private final SparseArray<LayoutHandlingAnimation> mLayoutHandlers = new SparseArray<>(0);
35+
private final SparseArray<ArrayList<Animation>> mDeleteAnimationsByParentTag =
36+
new SparseArray<>();
3437

3538
private boolean mShouldAnimateLayout;
3639
private long mMaxAnimationDuration = -1;
@@ -113,6 +116,7 @@ public void applyLayoutUpdate(View view, int x, int y, int width, int height) {
113116

114117
// Update an ongoing animation if possible, otherwise the layout update would be ignored as
115118
// the existing animation would still animate to the old layout.
119+
// Note the view is already inserted into the view hierarchy.
116120
LayoutHandlingAnimation existingAnimation = mLayoutHandlers.get(reactTag);
117121
if (existingAnimation != null) {
118122
existingAnimation.onLayoutUpdate(x, y, width, height);
@@ -164,11 +168,14 @@ public void onAnimationRepeat(Animation animation) {}
164168
* Animate a view deletion using the layout animation configuration supplied during
165169
* initialization.
166170
*
171+
* @param parentReactTag tag of parent view of @param view. used to associate animation with for
172+
* canceling
167173
* @param view The view to animate.
168174
* @param listener Called once the animation is finished, should be used to completely remove the
169175
* view.
170176
*/
171-
public void deleteView(final View view, final LayoutAnimationListener listener) {
177+
public void deleteView(
178+
final int parentReactTag, final View view, final LayoutAnimationListener listener) {
172179
UiThreadUtil.assertOnUiThread();
173180

174181
Animation animation =
@@ -188,6 +195,10 @@ public void onAnimationRepeat(Animation anim) {}
188195

189196
@Override
190197
public void onAnimationEnd(Animation anim) {
198+
ArrayList<Animation> animations = mDeleteAnimationsByParentTag.get(parentReactTag);
199+
if (animations != null) {
200+
animations.remove(anim);
201+
}
191202
listener.onAnimationEnd();
192203
}
193204
});
@@ -198,7 +209,16 @@ public void onAnimationEnd(Animation anim) {
198209
mMaxAnimationDuration = animationDuration;
199210
}
200211

212+
// Update our tracking list of delete animations
213+
ArrayList<Animation> deleteAnimations = mDeleteAnimationsByParentTag.get(parentReactTag);
214+
if (deleteAnimations == null) {
215+
deleteAnimations = new ArrayList<>();
216+
mDeleteAnimationsByParentTag.put(parentReactTag, deleteAnimations);
217+
}
218+
deleteAnimations.add(animation);
219+
201220
view.startAnimation(animation);
221+
202222
} else {
203223
listener.onAnimationEnd();
204224
}
@@ -225,4 +245,23 @@ private void scheduleCompletionCallback(long delayMillis) {
225245
sCompletionHandler.postDelayed(mCompletionRunnable, delayMillis);
226246
}
227247
}
248+
249+
/**
250+
* Animate a view deletion using the layout animation configuration supplied during
251+
* initialization.
252+
*
253+
* @param viewTag tag of parent view that we're going to cancel all child animations.
254+
*/
255+
public void cancelAnimationsForViewTag(int viewTag) {
256+
ArrayList<Animation> animations = mDeleteAnimationsByParentTag.get(viewTag);
257+
if (animations == null) {
258+
return;
259+
}
260+
261+
for (int i = 0; i < animations.size(); i++) {
262+
animations.get(i).cancel();
263+
}
264+
265+
mDeleteAnimationsByParentTag.remove(viewTag);
266+
}
228267
}

0 commit comments

Comments
 (0)