diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactClippingViewGroupHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactClippingViewGroupHelper.java index 78e51eaa21b08c..e47c2618802997 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactClippingViewGroupHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactClippingViewGroupHelper.java @@ -7,6 +7,7 @@ package com.facebook.react.uimanager; import android.graphics.Rect; +import android.graphics.RectF; import android.view.View; import android.view.ViewParent; import javax.annotation.concurrent.NotThreadSafe; @@ -55,4 +56,47 @@ public static void calculateClippingRect(View view, Rect outputRect) { } view.getDrawingRect(outputRect); } + + public static boolean getChildVisibleRectHelper(View child, Rect r, android.graphics.Point offset, View parent, String overflow) { + // This is based on the Android ViewGroup implementation, modified to clip child rects + // if overflow is set to ViewProps.HIDDEN. This effectively solves Issue #23870 which + // appears to have been introduced by FLAG_CLIP_CHILDREN being forced false + // regardless of whether clipping is desired. + final RectF rect = new RectF(); + rect.set(r); + + child.getMatrix().mapRect(rect); + + final int dx = child.getLeft() - parent.getScrollX(); + final int dy = child.getTop() - parent.getScrollY(); + + rect.offset(dx, dy); + + if (offset != null) { + float[] position = new float[2]; + position[0] = offset.x; + position[1] = offset.y; + child.getMatrix().mapPoints(position); + offset.x = Math.round(position[0]) + dx; + offset.y = Math.round(position[1]) + dy; + } + + final int width = parent.getRight() - parent.getLeft(); + final int height = parent.getBottom() - parent.getTop(); + + boolean rectIsVisible = true; + + ViewParent grandparent = parent.getParent(); + if (grandparent == null || ViewProps.HIDDEN.equals(overflow)) { + rectIsVisible = rect.intersect(0, 0, width, height); + } + + r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top), + (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom)); + + if (rectIsVisible && grandparent != null) { + rectIsVisible = grandparent.getChildVisibleRect(parent, r, offset); + } + return rectIsVisible; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index b0c12831a01476..626509abd3ee7b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -491,6 +491,11 @@ public void getClippingRect(Rect outClippingRect) { outClippingRect.set(Assertions.assertNotNull(mClippingRect)); } + @Override + public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { + return ReactClippingViewGroupHelper.getChildVisibleRectHelper(child, r, offset, this, mOverflow); + } + private int getSnapInterval() { if (mSnapInterval != 0) { return mSnapInterval; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index db071fbb49ded7..4a274848f1da91 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -342,6 +342,11 @@ public void getClippingRect(Rect outClippingRect) { outClippingRect.set(Assertions.assertNotNull(mClippingRect)); } + @Override + public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { + return ReactClippingViewGroupHelper.getChildVisibleRectHelper(child, r, offset, this, mOverflow); + } + @Override public void fling(int velocityY) { // Workaround. diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index e6b8dcd9bdc1d8..75689340b29e35 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -455,6 +455,11 @@ private void updateSubviewClipStatus(View subview) { } } + @Override + public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { + return ReactClippingViewGroupHelper.getChildVisibleRectHelper(child, r, offset, this, mOverflow); + } + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh);