diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK index 2bc1f29ca12..0b06176f149 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK @@ -4,6 +4,7 @@ android_library( name = 'scroll', srcs = glob(['*.java']), deps = [ + YOGA_TARGET, react_native_dep('third-party/android/support/v4:lib-support-v4'), react_native_dep('third-party/java/infer-annotations:infer-annotations'), react_native_dep('third-party/java/jsr-305:jsr-305'), @@ -19,4 +20,3 @@ android_library( 'PUBLIC', ], ) - 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 592bcd774a6..61e8a4d86dd 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 @@ -18,6 +18,7 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.view.MotionEvent; import android.view.View; import android.widget.HorizontalScrollView; @@ -27,6 +28,7 @@ import com.facebook.react.uimanager.MeasureSpecAssertions; import com.facebook.react.uimanager.events.NativeGestureUtil; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; +import com.facebook.react.views.view.ReactViewBackgroundDrawable; /** * Similar to {@link ReactScrollView} but only supports horizontal scrolling. @@ -48,6 +50,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements private @Nullable String mScrollPerfTag; private @Nullable Drawable mEndBackground; private int mEndFillColor = Color.TRANSPARENT; + private @Nullable ReactViewBackgroundDrawable mReactBackgroundDrawable; public ReactHorizontalScrollView(Context context) { this(context, null); @@ -312,4 +315,50 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements } smoothScrollTo(page * width, getScrollY()); } + + @Override + public void setBackgroundColor(int color) { + if (color == Color.TRANSPARENT && mReactBackgroundDrawable == null) { + // don't do anything, no need to allocate ReactBackgroundDrawable for transparent background + } else { + getOrCreateReactViewBackground().setColor(color); + } + } + + public void setBorderWidth(int position, float width) { + getOrCreateReactViewBackground().setBorderWidth(position, width); + } + + public void setBorderColor(int position, float color, float alpha) { + getOrCreateReactViewBackground().setBorderColor(position, color, alpha); + } + + public void setBorderRadius(float borderRadius) { + getOrCreateReactViewBackground().setRadius(borderRadius); + } + + public void setBorderRadius(float borderRadius, int position) { + getOrCreateReactViewBackground().setRadius(borderRadius, position); + } + + public void setBorderStyle(@Nullable String style) { + getOrCreateReactViewBackground().setBorderStyle(style); + } + + private ReactViewBackgroundDrawable getOrCreateReactViewBackground() { + if (mReactBackgroundDrawable == null) { + mReactBackgroundDrawable = new ReactViewBackgroundDrawable(); + Drawable backgroundDrawable = getBackground(); + super.setBackground(null); // required so that drawable callback is cleared before we add the + // drawable back as a part of LayerDrawable + if (backgroundDrawable == null) { + super.setBackground(mReactBackgroundDrawable); + } else { + LayerDrawable layerDrawable = + new LayerDrawable(new Drawable[]{mReactBackgroundDrawable, backgroundDrawable}); + super.setBackground(layerDrawable); + } + } + return mReactBackgroundDrawable; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index 2b0fe746e2e..24996edcf32 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -16,10 +16,15 @@ import android.view.View; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.PixelUtil; +import com.facebook.react.uimanager.Spacing; +import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; +import com.facebook.react.uimanager.annotations.ReactPropGroup; +import com.facebook.yoga.YogaConstants; /** * View manager for {@link ReactHorizontalScrollView} components. @@ -34,6 +39,10 @@ public class ReactHorizontalScrollViewManager protected static final String REACT_CLASS = "AndroidHorizontalScrollView"; + private static final int[] SPACING_TYPES = { + Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM, + }; + private @Nullable FpsListener mFpsListener = null; public ReactHorizontalScrollViewManager() { @@ -150,4 +159,52 @@ public class ReactHorizontalScrollViewManager public void setBottomFillColor(ReactHorizontalScrollView view, int color) { view.setEndFillColor(color); } + + @ReactPropGroup(names = { + ViewProps.BORDER_RADIUS, + ViewProps.BORDER_TOP_LEFT_RADIUS, + ViewProps.BORDER_TOP_RIGHT_RADIUS, + ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, + ViewProps.BORDER_BOTTOM_LEFT_RADIUS + }, defaultFloat = YogaConstants.UNDEFINED) + public void setBorderRadius(ReactHorizontalScrollView view, int index, float borderRadius) { + if (!YogaConstants.isUndefined(borderRadius)) { + borderRadius = PixelUtil.toPixelFromDIP(borderRadius); + } + + if (index == 0) { + view.setBorderRadius(borderRadius); + } else { + view.setBorderRadius(borderRadius, index - 1); + } + } + + @ReactProp(name = "borderStyle") + public void setBorderStyle(ReactHorizontalScrollView view, @Nullable String borderStyle) { + view.setBorderStyle(borderStyle); + } + + @ReactPropGroup(names = { + ViewProps.BORDER_WIDTH, + ViewProps.BORDER_LEFT_WIDTH, + ViewProps.BORDER_RIGHT_WIDTH, + ViewProps.BORDER_TOP_WIDTH, + ViewProps.BORDER_BOTTOM_WIDTH, + }, defaultFloat = YogaConstants.UNDEFINED) + public void setBorderWidth(ReactHorizontalScrollView view, int index, float width) { + if (!YogaConstants.isUndefined(width)) { + width = PixelUtil.toPixelFromDIP(width); + } + view.setBorderWidth(SPACING_TYPES[index], width); + } + + @ReactPropGroup(names = { + "borderColor", "borderLeftColor", "borderRightColor", "borderTopColor", "borderBottomColor" + }, customType = "Color") + public void setBorderColor(ReactHorizontalScrollView view, int index, Integer color) { + float rgbComponent = + color == null ? YogaConstants.UNDEFINED : (float) ((int)color & 0x00FFFFFF); + float alphaComponent = color == null ? YogaConstants.UNDEFINED : (float) ((int)color >>> 24); + view.setBorderColor(SPACING_TYPES[index], rgbComponent, alphaComponent); + } } 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 ae210a63669..2a5d5e428fd 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 @@ -18,6 +18,7 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.util.Log; import android.view.MotionEvent; import android.view.View; @@ -32,6 +33,7 @@ import com.facebook.react.uimanager.events.NativeGestureUtil; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.views.view.ReactViewBackgroundDrawable; /** * A simple subclass of ScrollView that doesn't dispatch measure and layout to its children and has @@ -60,6 +62,7 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou private @Nullable Drawable mEndBackground; private int mEndFillColor = Color.TRANSPARENT; private View mContentView; + private @Nullable ReactViewBackgroundDrawable mReactBackgroundDrawable; public ReactScrollView(ReactContext context) { this(context, null); @@ -380,4 +383,49 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou scrollTo(getScrollX(), maxScrollY); } } + + public void setBackgroundColor(int color) { + if (color == Color.TRANSPARENT && mReactBackgroundDrawable == null) { + // don't do anything, no need to allocate ReactBackgroundDrawable for transparent background + } else { + getOrCreateReactViewBackground().setColor(color); + } + } + + public void setBorderWidth(int position, float width) { + getOrCreateReactViewBackground().setBorderWidth(position, width); + } + + public void setBorderColor(int position, float color, float alpha) { + getOrCreateReactViewBackground().setBorderColor(position, color, alpha); + } + + public void setBorderRadius(float borderRadius) { + getOrCreateReactViewBackground().setRadius(borderRadius); + } + + public void setBorderRadius(float borderRadius, int position) { + getOrCreateReactViewBackground().setRadius(borderRadius, position); + } + + public void setBorderStyle(@Nullable String style) { + getOrCreateReactViewBackground().setBorderStyle(style); + } + + private ReactViewBackgroundDrawable getOrCreateReactViewBackground() { + if (mReactBackgroundDrawable == null) { + mReactBackgroundDrawable = new ReactViewBackgroundDrawable(); + Drawable backgroundDrawable = getBackground(); + super.setBackground(null); // required so that drawable callback is cleared before we add the + // drawable back as a part of LayerDrawable + if (backgroundDrawable == null) { + super.setBackground(mReactBackgroundDrawable); + } else { + LayerDrawable layerDrawable = + new LayerDrawable(new Drawable[]{mReactBackgroundDrawable, backgroundDrawable}); + super.setBackground(layerDrawable); + } + } + return mReactBackgroundDrawable; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index c70f8cebc23..924675c56bf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -19,10 +19,15 @@ import android.view.View; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.PixelUtil; +import com.facebook.react.uimanager.Spacing; +import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; +import com.facebook.react.uimanager.annotations.ReactPropGroup; +import com.facebook.yoga.YogaConstants; /** * View manager for {@link ReactScrollView} components. @@ -37,6 +42,10 @@ public class ReactScrollViewManager protected static final String REACT_CLASS = "RCTScrollView"; + private static final int[] SPACING_TYPES = { + Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM, + }; + private @Nullable FpsListener mFpsListener = null; public ReactScrollViewManager() { @@ -139,6 +148,53 @@ public class ReactScrollViewManager scrollView.scrollTo(data.mDestX, data.mDestY); } } + @ReactPropGroup(names = { + ViewProps.BORDER_RADIUS, + ViewProps.BORDER_TOP_LEFT_RADIUS, + ViewProps.BORDER_TOP_RIGHT_RADIUS, + ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, + ViewProps.BORDER_BOTTOM_LEFT_RADIUS + }, defaultFloat = YogaConstants.UNDEFINED) + public void setBorderRadius(ReactScrollView view, int index, float borderRadius) { + if (!YogaConstants.isUndefined(borderRadius)) { + borderRadius = PixelUtil.toPixelFromDIP(borderRadius); + } + + if (index == 0) { + view.setBorderRadius(borderRadius); + } else { + view.setBorderRadius(borderRadius, index - 1); + } + } + + @ReactProp(name = "borderStyle") + public void setBorderStyle(ReactScrollView view, @Nullable String borderStyle) { + view.setBorderStyle(borderStyle); + } + + @ReactPropGroup(names = { + ViewProps.BORDER_WIDTH, + ViewProps.BORDER_LEFT_WIDTH, + ViewProps.BORDER_RIGHT_WIDTH, + ViewProps.BORDER_TOP_WIDTH, + ViewProps.BORDER_BOTTOM_WIDTH, + }, defaultFloat = YogaConstants.UNDEFINED) + public void setBorderWidth(ReactScrollView view, int index, float width) { + if (!YogaConstants.isUndefined(width)) { + width = PixelUtil.toPixelFromDIP(width); + } + view.setBorderWidth(SPACING_TYPES[index], width); + } + + @ReactPropGroup(names = { + "borderColor", "borderLeftColor", "borderRightColor", "borderTopColor", "borderBottomColor" + }, customType = "Color") + public void setBorderColor(ReactScrollView view, int index, Integer color) { + float rgbComponent = + color == null ? YogaConstants.UNDEFINED : (float) ((int)color & 0x00FFFFFF); + float alphaComponent = color == null ? YogaConstants.UNDEFINED : (float) ((int)color >>> 24); + view.setBorderColor(SPACING_TYPES[index], rgbComponent, alphaComponent); + } @Override public void scrollToEnd(