diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupDrawingOrderHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupDrawingOrderHelper.java index 96448f6c01a277..2bd1d754f3a398 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupDrawingOrderHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupDrawingOrderHelper.java @@ -10,6 +10,8 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.Nullable; +import com.facebook.common.logging.FLog; +import com.facebook.react.common.ReactConstants; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -65,6 +67,17 @@ public boolean shouldEnableCustomDrawingOrder() { * ViewGroup#getChildDrawingOrder}. */ public int getChildDrawingOrder(int childCount, int index) { + if (mDrawingOrderIndices != null + && (index >= mDrawingOrderIndices.length || mDrawingOrderIndices[index] >= childCount)) { + FLog.w( + ReactConstants.TAG, + "getChildDrawingOrder index out of bounds! Please check any custom view manipulations you" + + " may have done. childCount = %d, index = %d", + childCount, + index); + update(); + } + if (mDrawingOrderIndices == null) { ArrayList viewsToSort = new ArrayList<>(); for (int i = 0; i < childCount; i++) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index d21362d48fb729..6bd724ecb3424d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -418,10 +418,10 @@ private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFa if (!intersects && child.getParent() != null && !isAnimating) { // We can try saving on invalidate call here as the view that we remove is out of visible area // therefore invalidation is not necessary. - super.removeViewsInLayout(idx - clippedSoFar, 1); + removeViewsInLayout(idx - clippedSoFar, 1); needUpdateClippingRecursive = true; } else if (intersects && child.getParent() == null) { - super.addViewInLayout(child, idx - clippedSoFar, sDefaultLayoutParam, true); + addViewInLayout(child, idx - clippedSoFar, sDefaultLayoutParam, true); invalidate(); needUpdateClippingRecursive = true; } else if (intersects) { @@ -499,23 +499,18 @@ private boolean customDrawOrderDisabled() { return ViewUtil.getUIManagerType(getId()) == UIManagerType.FABRIC; } - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { - // This will get called for every overload of addView so there is not need to override every - // method. + private void handleAddView(View view) { + UiThreadUtil.assertOnUiThread(); if (!customDrawOrderDisabled()) { - getDrawingOrderHelper().handleAddView(child); + getDrawingOrderHelper().handleAddView(view); setChildrenDrawingOrderEnabled(getDrawingOrderHelper().shouldEnableCustomDrawingOrder()); } else { setChildrenDrawingOrderEnabled(false); } - - super.addView(child, index, params); } - @Override - public void removeView(View view) { + private void handleRemoveView(View view) { UiThreadUtil.assertOnUiThread(); if (!customDrawOrderDisabled()) { @@ -524,22 +519,60 @@ public void removeView(View view) { } else { setChildrenDrawingOrderEnabled(false); } + } + + private void handleRemoveViews(int start, int count) { + int endIndex = start + count; + for (int index = start; index < endIndex; index++) { + if (index < getChildCount()) { + handleRemoveView(getChildAt(index)); + } + } + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + // This will get called for every overload of addView so there is not need to override every + // method. + handleAddView(child); + super.addView(child, index, params); + } + @Override + protected boolean addViewInLayout( + View child, int index, LayoutParams params, boolean preventRequestLayout) { + handleAddView(child); + return super.addViewInLayout(child, index, params, preventRequestLayout); + } + + @Override + public void removeView(View view) { + handleRemoveView(view); super.removeView(view); } @Override public void removeViewAt(int index) { - UiThreadUtil.assertOnUiThread(); + handleRemoveView(getChildAt(index)); + super.removeViewAt(index); + } - if (!customDrawOrderDisabled()) { - getDrawingOrderHelper().handleRemoveView(getChildAt(index)); - setChildrenDrawingOrderEnabled(getDrawingOrderHelper().shouldEnableCustomDrawingOrder()); - } else { - setChildrenDrawingOrderEnabled(false); - } + @Override + public void removeViewInLayout(View view) { + handleRemoveView(view); + super.removeViewInLayout(view); + } - super.removeViewAt(index); + @Override + public void removeViewsInLayout(int start, int count) { + handleRemoveViews(start, count); + super.removeViewsInLayout(start, count); + } + + @Override + public void removeViews(int start, int count) { + handleRemoveViews(start, count); + super.removeViews(start, count); } @Override @@ -663,7 +696,7 @@ public void run() { clippedSoFar++; } } - super.removeViewsInLayout(index - clippedSoFar, 1); + removeViewsInLayout(index - clippedSoFar, 1); } removeFromArray(index); }