From bc9168d4caee3c852b690cb11f697de6a002e101 Mon Sep 17 00:00:00 2001 From: Xin Chen Date: Mon, 20 Dec 2021 18:42:27 -0800 Subject: [PATCH] Add overflowInset to RN Android ViewGroup as separate mount instruction Summary: This diff adds `overflowInset` values in RN Android. These values are used to give an enlarged boundary of a view group that also contains all its children layout. Here is [the post](https://fb.workplace.com/groups/yogalayout/permalink/2264980363573947/) that discuss more on why this is useful. I steal the pic in that post here as TLDR: {F687030994} In the above case, we will get overflowInset for ViewGroup A as something like `top: 0, right: -20, bottom: -20, left: 0`. This has been added in the [Fabric core](https://fburl.com/code/f8c5tg7b) and [in IOS](https://fburl.com/code/vkh0hpt6). In Android, since we used to ignore all event coordinates outside of a ViewGroup boundary, this is not an issue. However, that caused unregistered touch area problem and got fixed in D30104853 (https://github.com/facebook/react-native/commit/e35a963bfb93bbbdd92f4dd74d14e2ad6df5e14a), which dropped the boundary check and made the hit test algorithm in [TouchTargetHelper.java](https://fburl.com/code/dj8jiz22) worse as we now need to explore all the child node under ReactRootNode. This perf issue is getting obvious when a view loads too many items, which matches our experience with "Hover getting slow after scrolling", "Hover getting slow after going back from PDP view", and "The saved list view (in Explore) is very fast (because it has very few components)" To fix this issue, I added the support to `overflowInset` to RN Android by 1. Sending the `overflowInset` values from Binding.cpp in RN Android as a separate mount instruction 2. Update `IntBufferBatchMountItem.java` to read the int buffer sent over JNI, and pass the `overflowInset` values to `SurfaceMountingManager.java` 3. Creating new interface `ReactOverflowViewWithInset.java` and extending the existing `ReactOverflowView.java` usages 4. Adding implementation of getter and setter for `overflowInset` in various views 5. Update `TouchTargetHelper.java` to read the values and check boundaries before exploring ViewGroup's children Note that in #3 I didn't change `ReactOverflowView.java` interface directly. I am concerned about backward compatibility issues in case this interface is being used in OSS. I suggest we deprecate it as we are not using it anymore in our code. Changelog: [Internal][Android] Reviewed By: JoshuaGross Differential Revision: D33133977 fbshipit-source-id: 64e3e837fe7ca6e6dbdbc836ab0615182e10f28c --- .../react/fabric/jni/FabricMountItem.cpp | 4 ++ .../react/fabric/jni/FabricMountItem.h | 6 +- .../fabric/jni/FabricMountingManager.cpp | 59 ++++++++++++++++++- .../mounting/SurfaceMountingManager.java | 30 ++++++++++ .../mountitems/IntBufferBatchMountItem.java | 24 ++++++++ .../uimanager/ReactOverflowViewWithInset.java | 33 +++++++++++ .../react/uimanager/TouchTargetHelper.java | 20 ++++++- .../scroll/ReactHorizontalScrollView.java | 15 ++++- .../react/views/scroll/ReactScrollView.java | 15 ++++- .../react/views/view/ReactViewGroup.java | 15 ++++- 10 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactOverflowViewWithInset.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.cpp index 2d3dda6596b..c678cbdc5b2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.cpp @@ -45,6 +45,10 @@ CppMountItem CppMountItem::UpdatePaddingMountItem( ShadowView const &shadowView) { return {CppMountItem::Type::UpdatePadding, {}, {}, shadowView, -1}; } +CppMountItem CppMountItem::UpdateOverflowInsetMountItem( + ShadowView const &shadowView) { + return {CppMountItem::Type::UpdateOverflowInset, {}, {}, shadowView, -1}; +} } // namespace react } // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.h index 6a851270ff1..5c85738d708 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountItem.h @@ -45,6 +45,9 @@ struct CppMountItem final { static CppMountItem UpdatePaddingMountItem(ShadowView const &shadowView); + static CppMountItem UpdateOverflowInsetMountItem( + ShadowView const &shadowView); + #pragma mark - Type enum Type { @@ -58,7 +61,8 @@ struct CppMountItem final { UpdateState = 64, UpdateLayout = 128, UpdateEventEmitter = 256, - UpdatePadding = 512 + UpdatePadding = 512, + UpdateOverflowInset = 1024 }; #pragma mark - Fields diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountingManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountingManager.cpp index e78540767a2..68bf552f04e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountingManager.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/FabricMountingManager.cpp @@ -43,6 +43,8 @@ static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) { return 5; // tag, top, left, bottom, right case CppMountItem::Type::UpdateLayout: return 6; // tag, x, y, w, h, DisplayType + case CppMountItem::Type::UpdateOverflowInset: + return 5; // tag, left, top, right, bottom case CppMountItem::Undefined: case CppMountItem::Multiple: return -1; @@ -84,6 +86,7 @@ static inline void computeBufferSizes( std::vector &cppUpdateStateMountItems, std::vector &cppUpdatePaddingMountItems, std::vector &cppUpdateLayoutMountItems, + std::vector &cppUpdateOverflowInsetMountItems, std::vector &cppUpdateEventEmitterMountItems) { CppMountItem::Type lastType = CppMountItem::Type::Undefined; int numSameType = 0; @@ -128,6 +131,11 @@ static inline void computeBufferSizes( cppUpdateLayoutMountItems.size(), batchMountItemIntsSize, batchMountItemObjectsSize); + updateBufferSizes( + CppMountItem::Type::UpdateOverflowInset, + cppUpdateOverflowInsetMountItems.size(), + batchMountItemIntsSize, + batchMountItemObjectsSize); updateBufferSizes( CppMountItem::Type::UpdateEventEmitter, cppUpdateEventEmitterMountItems.size(), @@ -232,6 +240,7 @@ void FabricMountingManager::executeMount( std::vector cppUpdateStateMountItems; std::vector cppUpdatePaddingMountItems; std::vector cppUpdateLayoutMountItems; + std::vector cppUpdateOverflowInsetMountItems; std::vector cppUpdateEventEmitterMountItems; for (const auto &mutation : mutations) { @@ -293,6 +302,16 @@ void FabricMountingManager::executeMount( CppMountItem::UpdateLayoutMountItem( mutation.newChildShadowView)); } + + // OverflowInset: This is the values indicating boundaries including + // children of the current view. The layout of current view may not + // change, and we separate this part from layout mount items to not + // pack too much data there. + if (oldChildShadowView.layoutMetrics.overflowInset != + newChildShadowView.layoutMetrics.overflowInset) { + cppUpdateOverflowInsetMountItems.push_back( + CppMountItem::UpdateOverflowInsetMountItem(newChildShadowView)); + } } if (oldChildShadowView.eventEmitter != @@ -331,6 +350,13 @@ void FabricMountingManager::executeMount( // Layout cppUpdateLayoutMountItems.push_back( CppMountItem::UpdateLayoutMountItem(mutation.newChildShadowView)); + + // OverflowInset: This is the values indicating boundaries including + // children of the current view. The layout of current view may not + // change, and we separate this part from layout mount items to not + // pack too much data there. + cppUpdateOverflowInsetMountItems.push_back( + CppMountItem::UpdateOverflowInsetMountItem(newChildShadowView)); } // EventEmitter @@ -359,6 +385,7 @@ void FabricMountingManager::executeMount( cppUpdateStateMountItems, cppUpdatePaddingMountItems, cppUpdateLayoutMountItems, + cppUpdateOverflowInsetMountItems, cppUpdateEventEmitterMountItems); static auto createMountItemsIntBufferBatchContainer = @@ -407,7 +434,7 @@ void FabricMountingManager::executeMount( int intBufferPosition = 0; int objBufferPosition = 0; int prevMountItemType = -1; - jint temp[7]; + jint temp[6]; for (int i = 0; i < cppCommonMountItems.size(); i++) { const auto &mountItem = cppCommonMountItems[i]; const auto &mountItemType = mountItem.type; @@ -594,6 +621,36 @@ void FabricMountingManager::executeMount( intBufferPosition += 6; } } + if (!cppUpdateOverflowInsetMountItems.empty()) { + writeIntBufferTypePreamble( + CppMountItem::Type::UpdateOverflowInset, + cppUpdateOverflowInsetMountItems.size(), + env, + intBufferArray, + intBufferPosition); + + for (const auto &mountItem : cppUpdateOverflowInsetMountItems) { + auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics; + auto pointScaleFactor = layoutMetrics.pointScaleFactor; + auto overflowInset = layoutMetrics.overflowInset; + + int overflowInsetLeft = + round(scale(overflowInset.left, pointScaleFactor)); + int overflowInsetTop = round(scale(overflowInset.top, pointScaleFactor)); + int overflowInsetRight = + round(scale(overflowInset.right, pointScaleFactor)); + int overflowInsetBottom = + round(scale(overflowInset.bottom, pointScaleFactor)); + + temp[0] = mountItem.newChildShadowView.tag; + temp[1] = overflowInsetLeft; + temp[2] = overflowInsetTop; + temp[3] = overflowInsetRight; + temp[4] = overflowInsetBottom; + env->SetIntArrayRegion(intBufferArray, intBufferPosition, 5, temp); + intBufferPosition += 5; + } + } if (!cppUpdateEventEmitterMountItems.empty()) { writeIntBufferTypePreamble( CppMountItem::Type::UpdateEventEmitter, diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index ec082c37dd8..7b2051c92fe 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -32,6 +32,7 @@ import com.facebook.react.fabric.mounting.MountingManager.MountItemExecutor; import com.facebook.react.fabric.mounting.mountitems.MountItem; import com.facebook.react.touch.JSResponderHandler; import com.facebook.react.uimanager.IllegalViewOperationException; +import com.facebook.react.uimanager.ReactOverflowViewWithInset; import com.facebook.react.uimanager.ReactRoot; import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.RootView; @@ -758,6 +759,35 @@ public class SurfaceMountingManager { viewManager.setPadding(viewToUpdate, left, top, right, bottom); } + @UiThread + public void updateOverflowInset( + int reactTag, + int overflowInsetLeft, + int overflowInsetTop, + int overflowInsetRight, + int overflowInsetBottom) { + if (isStopped()) { + return; + } + + ViewState viewState = getViewState(reactTag); + // Do not layout Root Views + if (viewState.mIsRoot) { + return; + } + + View viewToUpdate = viewState.mView; + if (viewToUpdate == null) { + throw new IllegalStateException("Unable to find View for tag: " + reactTag); + } + + if (viewToUpdate instanceof ReactOverflowViewWithInset) { + ((ReactOverflowViewWithInset) viewToUpdate) + .setOverflowInset( + overflowInsetLeft, overflowInsetTop, overflowInsetRight, overflowInsetBottom); + } + } + @UiThread public void updateState(final int reactTag, @Nullable StateWrapper stateWrapper) { UiThreadUtil.assertOnUiThread(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index 038596c6ac4..f768453cb8e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -49,6 +49,7 @@ public class IntBufferBatchMountItem implements MountItem { static final int INSTRUCTION_UPDATE_LAYOUT = 128; static final int INSTRUCTION_UPDATE_EVENT_EMITTER = 256; static final int INSTRUCTION_UPDATE_PADDING = 512; + static final int INSTRUCTION_UPDATE_OVERFLOW_INSET = 1024; private final int mSurfaceId; private final int mCommitNumber; @@ -163,11 +164,25 @@ public class IntBufferBatchMountItem implements MountItem { int width = mIntBuffer[i++]; int height = mIntBuffer[i++]; int displayType = mIntBuffer[i++]; + surfaceMountingManager.updateLayout(reactTag, x, y, width, height, displayType); } else if (type == INSTRUCTION_UPDATE_PADDING) { surfaceMountingManager.updatePadding( mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); + } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { + int reactTag = mIntBuffer[i++]; + int overflowInsetLeft = mIntBuffer[i++]; + int overflowInsetTop = mIntBuffer[i++]; + int overflowInsetRight = mIntBuffer[i++]; + int overflowInsetBottom = mIntBuffer[i++]; + + surfaceMountingManager.updateOverflowInset( + reactTag, + overflowInsetLeft, + overflowInsetTop, + overflowInsetRight, + overflowInsetBottom); } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { surfaceMountingManager.updateEventEmitter( mIntBuffer[i++], castToEventEmitter(mObjBuffer[j++])); @@ -251,6 +266,15 @@ public class IntBufferBatchMountItem implements MountItem { mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++])); + } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { + s.append( + String.format( + "UPDATE OVERFLOWINSET [%d]: left:%d top:%d right:%d bottom:%d\n", + mIntBuffer[i++], + mIntBuffer[i++], + mIntBuffer[i++], + mIntBuffer[i++], + mIntBuffer[i++])); } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { j += 1; s.append(String.format("UPDATE EVENTEMITTER [%d]\n", mIntBuffer[i++])); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactOverflowViewWithInset.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactOverflowViewWithInset.java new file mode 100644 index 00000000000..e8f0e522f28 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactOverflowViewWithInset.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.uimanager; + +import android.graphics.Rect; +import android.view.View; + +/** + * Interface that should be implemented by {@link View} subclasses that support {@code overflow} + * style and want to use the overflowInset values. This allows the overflow information to be used + * by {@link TouchTargetHelper} to determine if a View is touchable. + */ +public interface ReactOverflowViewWithInset extends ReactOverflowView { + /** + * Get the overflow inset rect values which indicate the extensions to the boundaries of current + * view that wraps all of its children views + * + * @return Rect of integers indicating the left, top, right, bottom pixel extensions. The values + * are non-positive (indicating enlarged boundaries). + */ + Rect getOverflowInset(); + + /** + * Set the overflow inset rect values which indicate the extensions to the boundaries of current + * view that wraps all of its children views + */ + void setOverflowInset(int left, int top, int right, int bottom); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java index e96077eddec..9a1bc71f885 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java @@ -182,8 +182,14 @@ public class TouchTargetHelper { if (!isTouchPointInView(eventCoords[0], eventCoords[1], view)) { // We don't allow touches on views that are outside the bounds of an `overflow: hidden` and // `overflow: scroll` View. - if (view instanceof ReactOverflowView) { - @Nullable String overflow = ((ReactOverflowView) view).getOverflow(); + if (view instanceof ReactOverflowViewWithInset) { + // If the touch point is outside of the overflowinset for the view, we can safely ignore + // it. + if (!isTouchPointInViewWithOverflowInset(eventCoords[0], eventCoords[1], view)) { + return null; + } + + @Nullable String overflow = ((ReactOverflowViewWithInset) view).getOverflow(); if (ViewProps.HIDDEN.equals(overflow) || ViewProps.SCROLL.equals(overflow)) { return null; } @@ -253,6 +259,16 @@ public class TouchTargetHelper { } } + private static boolean isTouchPointInViewWithOverflowInset(float x, float y, View view) { + if (!(view instanceof ReactOverflowViewWithInset)) { + return false; + } + + final Rect overflowInset = ((ReactOverflowViewWithInset) view).getOverflowInset(); + return (x >= -overflowInset.left && x < view.getWidth() - overflowInset.right) + && (y >= -overflowInset.top && y < view.getHeight() - overflowInset.bottom); + } + /** * Returns the coordinates of a touch in the child View. It is transform aware and will invert the * transform Matrix to find the true local points This code is taken from {@link 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 d033e068712..bbb228d8fac 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 @@ -42,7 +42,7 @@ import com.facebook.react.uimanager.FabricViewStateManager; import com.facebook.react.uimanager.MeasureSpecAssertions; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; -import com.facebook.react.uimanager.ReactOverflowView; +import com.facebook.react.uimanager.ReactOverflowViewWithInset; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.events.NativeGestureUtil; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasFlingAnimator; @@ -57,7 +57,7 @@ import java.util.List; public class ReactHorizontalScrollView extends HorizontalScrollView implements ReactClippingViewGroup, FabricViewStateManager.HasFabricViewStateManager, - ReactOverflowView, + ReactOverflowViewWithInset, HasScrollState, HasFlingAnimator { @@ -77,6 +77,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView private final @Nullable OverScroller mScroller; private final VelocityHelper mVelocityHelper = new VelocityHelper(); private final Rect mRect = new Rect(); + private final Rect mOverflowInset = new Rect(); private boolean mActivelyScrolling; private @Nullable Rect mClippingRect; @@ -256,6 +257,16 @@ public class ReactHorizontalScrollView extends HorizontalScrollView return mOverflow; } + @Override + public void setOverflowInset(int left, int top, int right, int bottom) { + mOverflowInset.set(left, top, right, bottom); + } + + @Override + public Rect getOverflowInset() { + return mOverflowInset; + } + @Override protected void onDraw(Canvas canvas) { if (DEBUG_MODE) { 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 652ec951301..b029e951e1e 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 @@ -38,7 +38,7 @@ import com.facebook.react.uimanager.FabricViewStateManager; import com.facebook.react.uimanager.MeasureSpecAssertions; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; -import com.facebook.react.uimanager.ReactOverflowView; +import com.facebook.react.uimanager.ReactOverflowViewWithInset; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.events.NativeGestureUtil; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasFlingAnimator; @@ -60,7 +60,7 @@ public class ReactScrollView extends ScrollView ViewGroup.OnHierarchyChangeListener, View.OnLayoutChangeListener, FabricViewStateManager.HasFabricViewStateManager, - ReactOverflowView, + ReactOverflowViewWithInset, HasScrollState, HasFlingAnimator { @@ -73,6 +73,7 @@ public class ReactScrollView extends ScrollView private final @Nullable OverScroller mScroller; private final VelocityHelper mVelocityHelper = new VelocityHelper(); private final Rect mRect = new Rect(); // for reuse to avoid allocation + private final Rect mOverflowInset = new Rect(); private boolean mActivelyScrolling; private @Nullable Rect mClippingRect; @@ -231,6 +232,16 @@ public class ReactScrollView extends ScrollView return mOverflow; } + @Override + public void setOverflowInset(int left, int top, int right, int bottom) { + mOverflowInset.set(left, top, right, bottom); + } + + @Override + public Rect getOverflowInset() { + return mOverflowInset; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MeasureSpecAssertions.assertExplicitMeasureSpec(widthMeasureSpec, heightMeasureSpec); 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 8aedfecf772..d0d019a3f4b 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 @@ -44,7 +44,7 @@ import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactClippingProhibitedView; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; -import com.facebook.react.uimanager.ReactOverflowView; +import com.facebook.react.uimanager.ReactOverflowViewWithInset; import com.facebook.react.uimanager.ReactPointerEventsView; import com.facebook.react.uimanager.ReactZIndexedViewGroup; import com.facebook.react.uimanager.RootView; @@ -66,11 +66,12 @@ public class ReactViewGroup extends ViewGroup ReactPointerEventsView, ReactHitSlopView, ReactZIndexedViewGroup, - ReactOverflowView { + ReactOverflowViewWithInset { private static final int ARRAY_CAPACITY_INCREMENT = 12; private static final int DEFAULT_BACKGROUND_COLOR = Color.TRANSPARENT; private static final LayoutParams sDefaultLayoutParam = new ViewGroup.LayoutParams(0, 0); + private final Rect mOverflowInset = new Rect(); /* should only be used in {@link #updateClippingToRect} */ private static final Rect sHelperRect = new Rect(); @@ -726,6 +727,16 @@ public class ReactViewGroup extends ViewGroup return mOverflow; } + @Override + public void setOverflowInset(int left, int top, int right, int bottom) { + mOverflowInset.set(left, top, right, bottom); + } + + @Override + public Rect getOverflowInset() { + return mOverflowInset; + } + /** * Set the background for the view or remove the background. It calls {@link * #setBackground(Drawable)} or {@link #setBackgroundDrawable(Drawable)} based on the sdk version.