Adjust Layout Animation with pending deletion set

Summary:
Changelog: [Internal]
This solves the problem of viewToAdd indices being invalid if the deletes are asynchronous within the scope of one `manageChildren` call.

Since deletions are performed first, we keep a set of tags being deleted.
During view insertion, we iterate through and filter those tags out of our count.

Reviewed By: JoshuaGross

Differential Revision: D20324643

fbshipit-source-id: 150230428fcd65b8c43cc1f2331e9ce02d31fff9
This commit is contained in:
Luna Wei
2020-03-09 18:33:53 -07:00
committed by Facebook Github Bot
parent 0c7bd388f0
commit c938c0afbf
@@ -35,6 +35,8 @@ import com.facebook.react.uimanager.layoutanimation.LayoutAnimationListener;
import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
/**
@@ -363,6 +365,7 @@ public class NativeViewHierarchyManager {
@Nullable int[] tagsToDelete) {
UiThreadUtil.assertOnUiThread();
final Set<Integer> pendingDeletionTags = new HashSet<>();
mLayoutAnimator.cancelAnimationsForViewTag(tag);
final ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag);
@@ -446,6 +449,7 @@ public class NativeViewHierarchyManager {
}
if (mLayoutAnimationEnabled && mLayoutAnimator.shouldAnimateLayout(viewToDestroy)) {
pendingDeletionTags.add(tagToDelete);
mLayoutAnimator.deleteView(
tag,
viewToDestroy,
@@ -458,6 +462,7 @@ public class NativeViewHierarchyManager {
viewManager.removeView(viewToManage, viewToDestroy);
dropView(viewToDestroy);
pendingDeletionTags.remove(viewToDestroy.getId());
}
});
} else {
@@ -478,7 +483,24 @@ public class NativeViewHierarchyManager {
+ constructManageChildrenErrorMessage(
viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
}
viewManager.addView(viewToManage, viewToAdd, viewAtIndex.mIndex);
int normalizedIndex = viewAtIndex.mIndex;
if (!pendingDeletionTags.isEmpty()) {
normalizedIndex = 0;
int counter = 0;
while (normalizedIndex < viewToManage.getChildCount()) {
if (counter == viewAtIndex.mIndex) {
break;
}
View v = viewToManage.getChildAt(normalizedIndex);
if (!pendingDeletionTags.contains(v.getId())) {
counter++;
}
normalizedIndex++;
}
}
viewManager.addView(viewToManage, viewToAdd, normalizedIndex);
}
}
}