From 42152a3fa3f949f5112461753eb44a436355dfb1 Mon Sep 17 00:00:00 2001 From: Alexander Kawrykow Date: Thu, 3 Oct 2019 15:33:21 -0700 Subject: [PATCH] Support removeClippedSubviews for horizontal ScrollViews Summary: Currently, horizontal `ScrollViews` don't properly support `removeClippedSubviews`. This is because the container view, `ReactHorizontalScrollContainerView` extends from regular `ViewGroup` instead of `ReactViewGroup` so doesn't have all the logic around clipping children. Moreover, the `ReactHorizontalScrollContainerViewManager` doesn't actually support the `removeClippedSubviews` prop This change: - Makes `ReactHorizontalScrollContainerView` extend from `ReactViewGroup` while maintaining the special logic around RTL scrolling - Factors out a common `ReactClippingViewManager` which will be used to bridge all components which extend `ReactViewGroup` and support clipping. It has the logic for adding/removing children and getting child counts while considering clipped subviews - `ReactViewManager` now extends this new `ReactClippingViewManager` - `ReactHorizontalScrollContainerViewManager` also extends `ReactClippingViewManager` Reviewed By: JoshuaGross Differential Revision: D17708630 fbshipit-source-id: d257566ee54ad46f6d62f176a657c596bba96aa4 --- .../ReactHorizontalScrollContainerView.java | 4 +- ...tHorizontalScrollContainerViewManager.java | 4 +- .../views/view/ReactClippingViewManager.java | 78 +++++++++++++++++++ .../react/views/view/ReactViewManager.java | 63 +-------------- 4 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewManager.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java index f64600b13a6102..2273a777751603 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java @@ -6,13 +6,13 @@ package com.facebook.react.views.scroll; import android.content.Context; -import android.view.ViewGroup; import android.widget.HorizontalScrollView; import androidx.core.view.ViewCompat; import com.facebook.react.modules.i18nmanager.I18nUtil; +import com.facebook.react.views.view.ReactViewGroup; /** Container of Horizontal scrollViews that supports RTL scrolling. */ -public class ReactHorizontalScrollContainerView extends ViewGroup { +public class ReactHorizontalScrollContainerView extends ReactViewGroup { private int mLayoutDirection; private int mCurrentWidth; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.java index 3189dde8153b86..dda24486b74f4f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.java @@ -7,12 +7,12 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.views.view.ReactClippingViewManager; /** View manager for {@link ReactHorizontalScrollContainerView} components. */ @ReactModule(name = ReactHorizontalScrollContainerViewManager.REACT_CLASS) public class ReactHorizontalScrollContainerViewManager - extends ViewGroupManager { + extends ReactClippingViewManager { public static final String REACT_CLASS = "AndroidHorizontalScrollContentView"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewManager.java new file mode 100644 index 00000000000000..b00d0979bb088f --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewManager.java @@ -0,0 +1,78 @@ +// 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.views.view; + +import android.view.View; +import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.uimanager.annotations.ReactProp; + +/** + * View manager which handles clipped subviews. Useful for custom views which extends from {@link + * com.facebook.react.views.view.ReactViewGroup} + */ +public abstract class ReactClippingViewManager + extends ViewGroupManager { + + @ReactProp( + name = com.facebook.react.uimanager.ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS) + public void setRemoveClippedSubviews(T view, boolean removeClippedSubviews) { + view.setRemoveClippedSubviews(removeClippedSubviews); + } + + @Override + public void addView(T parent, View child, int index) { + boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); + if (removeClippedSubviews) { + parent.addViewWithSubviewClippingEnabled(child, index); + } else { + parent.addView(child, index); + } + } + + @Override + public int getChildCount(T parent) { + boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); + if (removeClippedSubviews) { + return parent.getAllChildrenCount(); + } else { + return parent.getChildCount(); + } + } + + @Override + public View getChildAt(T parent, int index) { + boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); + if (removeClippedSubviews) { + return parent.getChildAtWithSubviewClippingEnabled(index); + } else { + return parent.getChildAt(index); + } + } + + @Override + public void removeViewAt(T parent, int index) { + boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); + if (removeClippedSubviews) { + View child = getChildAt(parent, index); + if (child.getParent() != null) { + parent.removeView(child); + } + parent.removeViewWithSubviewClippingEnabled(child); + } else { + parent.removeViewAt(index); + } + } + + @Override + public void removeAllViews(T parent) { + boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); + if (removeClippedSubviews) { + parent.removeAllViewsWithSubviewClippingEnabled(); + } else { + parent.removeAllViews(); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java index 1e9fea92381595..382fc79fc84733 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java @@ -24,7 +24,6 @@ import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.annotations.ReactPropGroup; @@ -35,7 +34,7 @@ /** View manager for AndroidViews (plain React Views). */ @ReactModule(name = ReactViewManager.REACT_CLASS) -public class ReactViewManager extends ViewGroupManager { +public class ReactViewManager extends ReactClippingViewManager { @VisibleForTesting public static final String REACT_CLASS = ViewProps.VIEW_CLASS_NAME; @@ -182,12 +181,6 @@ public void setNativeForeground(ReactViewGroup view, @Nullable ReadableMap fg) { fg == null ? null : ReactDrawableHelper.createDrawableFromJSDescription(view, fg)); } - @ReactProp( - name = com.facebook.react.uimanager.ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS) - public void setRemoveClippedSubviews(ReactViewGroup view, boolean removeClippedSubviews) { - view.setRemoveClippedSubviews(removeClippedSubviews); - } - @ReactProp(name = ViewProps.NEEDS_OFFSCREEN_ALPHA_COMPOSITING) public void setNeedsOffscreenAlphaCompositing( ReactViewGroup view, boolean needsOffscreenAlphaCompositing) { @@ -354,58 +347,4 @@ private void handleHotspotUpdate(ReactViewGroup root, @Nullable ReadableArray ar root.drawableHotspotChanged(x, y); } } - - @Override - public void addView(ReactViewGroup parent, View child, int index) { - boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); - if (removeClippedSubviews) { - parent.addViewWithSubviewClippingEnabled(child, index); - } else { - parent.addView(child, index); - } - } - - @Override - public int getChildCount(ReactViewGroup parent) { - boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); - if (removeClippedSubviews) { - return parent.getAllChildrenCount(); - } else { - return parent.getChildCount(); - } - } - - @Override - public View getChildAt(ReactViewGroup parent, int index) { - boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); - if (removeClippedSubviews) { - return parent.getChildAtWithSubviewClippingEnabled(index); - } else { - return parent.getChildAt(index); - } - } - - @Override - public void removeViewAt(ReactViewGroup parent, int index) { - boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); - if (removeClippedSubviews) { - View child = getChildAt(parent, index); - if (child.getParent() != null) { - parent.removeView(child); - } - parent.removeViewWithSubviewClippingEnabled(child); - } else { - parent.removeViewAt(index); - } - } - - @Override - public void removeAllViews(ReactViewGroup parent) { - boolean removeClippedSubviews = parent.getRemoveClippedSubviews(); - if (removeClippedSubviews) { - parent.removeAllViewsWithSubviewClippingEnabled(); - } else { - parent.removeAllViews(); - } - } }