Skip to content
Permalink
Browse files
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
  • Loading branch information
Alexander Kawrykow authored and facebook-github-bot committed Oct 3, 2019
1 parent 21f1cce commit 42152a3fa3f949f5112461753eb44a436355dfb1
Showing 4 changed files with 83 additions and 66 deletions.
@@ -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;
@@ -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<ReactHorizontalScrollContainerView> {
extends ReactClippingViewManager<ReactHorizontalScrollContainerView> {

public static final String REACT_CLASS = "AndroidHorizontalScrollContentView";

@@ -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<T extends ReactViewGroup>
extends ViewGroupManager<T> {

@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();
}
}
}
@@ -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<ReactViewGroup> {
public class ReactViewManager extends ReactClippingViewManager<ReactViewGroup> {

@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();
}
}
}

0 comments on commit 42152a3

Please sign in to comment.