diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java index 8f68c957208..a0d172ad389 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java @@ -9,8 +9,6 @@ package com.facebook.react.views.view; import android.annotation.TargetApi; import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Build; @@ -30,7 +28,8 @@ public class ReactDrawableHelper { @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static Drawable createDrawableFromJSDescription( - Context context, ReadableMap drawableDescriptionDict) { + ReactViewGroup view, ReadableMap drawableDescriptionDict) { + Context context = view.getContext(); String type = drawableDescriptionDict.getString("type"); if ("ThemeAttrAndroid".equals(type)) { String attr = drawableDescriptionDict.getString("attribute"); @@ -75,7 +74,7 @@ public class ReactDrawableHelper { if (!drawableDescriptionDict.hasKey("borderless") || drawableDescriptionDict.isNull("borderless") || !drawableDescriptionDict.getBoolean("borderless")) { - mask = new ColorDrawable(Color.WHITE); + mask = view.getBorderRadiusMask(); } ColorStateList colorStateList = new ColorStateList(new int[][] {new int[] {}}, new int[] {color}); 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 4cb0e95643e..e6b8dcd9bdc 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 @@ -18,12 +18,15 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; import android.os.Build; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewStructure; import android.view.animation.Animation; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; @@ -286,6 +289,31 @@ public class ReactViewGroup extends ViewGroup getOrCreateReactViewBackground().setBorderStyle(style); } + @NonNull + public Drawable getBorderRadiusMask() { + final float[] outerRadii; + if (mReactBackgroundDrawable == null) { + outerRadii = null; + } else { + final float[] borderRadii = getBorderRadii(mReactBackgroundDrawable); + outerRadii = + new float[] { + borderRadii[0], + borderRadii[0], + borderRadii[1], + borderRadii[1], + borderRadii[2], + borderRadii[2], + borderRadii[3], + borderRadii[3] + }; + } + final ShapeDrawable shapeDrawable = + new ShapeDrawable(new RoundRectShape(outerRadii, null, null)); + shapeDrawable.getPaint().setColor(Color.WHITE); + return shapeDrawable; + } + @Override public void setRemoveClippedSubviews(boolean removeClippedSubviews) { if (removeClippedSubviews == mRemoveClippedSubviews) { @@ -732,92 +760,11 @@ public class ReactViewGroup extends ViewGroup bottom -= borderWidth.bottom; } - final float borderRadius = mReactBackgroundDrawable.getFullBorderRadius(); - float topLeftBorderRadius = - mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( - borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_LEFT); - float topRightBorderRadius = - mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( - borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_RIGHT); - float bottomLeftBorderRadius = - mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( - borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_LEFT); - float bottomRightBorderRadius = - mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( - borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_RIGHT); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - final boolean isRTL = mLayoutDirection == View.LAYOUT_DIRECTION_RTL; - float topStartBorderRadius = - mReactBackgroundDrawable.getBorderRadius( - ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_START); - float topEndBorderRadius = - mReactBackgroundDrawable.getBorderRadius( - ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_END); - float bottomStartBorderRadius = - mReactBackgroundDrawable.getBorderRadius( - ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_START); - float bottomEndBorderRadius = - mReactBackgroundDrawable.getBorderRadius( - ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_END); - - if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(getContext())) { - if (YogaConstants.isUndefined(topStartBorderRadius)) { - topStartBorderRadius = topLeftBorderRadius; - } - - if (YogaConstants.isUndefined(topEndBorderRadius)) { - topEndBorderRadius = topRightBorderRadius; - } - - if (YogaConstants.isUndefined(bottomStartBorderRadius)) { - bottomStartBorderRadius = bottomLeftBorderRadius; - } - - if (YogaConstants.isUndefined(bottomEndBorderRadius)) { - bottomEndBorderRadius = bottomRightBorderRadius; - } - - final float directionAwareTopLeftRadius = - isRTL ? topEndBorderRadius : topStartBorderRadius; - final float directionAwareTopRightRadius = - isRTL ? topStartBorderRadius : topEndBorderRadius; - final float directionAwareBottomLeftRadius = - isRTL ? bottomEndBorderRadius : bottomStartBorderRadius; - final float directionAwareBottomRightRadius = - isRTL ? bottomStartBorderRadius : bottomEndBorderRadius; - - topLeftBorderRadius = directionAwareTopLeftRadius; - topRightBorderRadius = directionAwareTopRightRadius; - bottomLeftBorderRadius = directionAwareBottomLeftRadius; - bottomRightBorderRadius = directionAwareBottomRightRadius; - } else { - final float directionAwareTopLeftRadius = - isRTL ? topEndBorderRadius : topStartBorderRadius; - final float directionAwareTopRightRadius = - isRTL ? topStartBorderRadius : topEndBorderRadius; - final float directionAwareBottomLeftRadius = - isRTL ? bottomEndBorderRadius : bottomStartBorderRadius; - final float directionAwareBottomRightRadius = - isRTL ? bottomStartBorderRadius : bottomEndBorderRadius; - - if (!YogaConstants.isUndefined(directionAwareTopLeftRadius)) { - topLeftBorderRadius = directionAwareTopLeftRadius; - } - - if (!YogaConstants.isUndefined(directionAwareTopRightRadius)) { - topRightBorderRadius = directionAwareTopRightRadius; - } - - if (!YogaConstants.isUndefined(directionAwareBottomLeftRadius)) { - bottomLeftBorderRadius = directionAwareBottomLeftRadius; - } - - if (!YogaConstants.isUndefined(directionAwareBottomRightRadius)) { - bottomRightBorderRadius = directionAwareBottomRightRadius; - } - } - } + final float borderRadii[] = getBorderRadii(mReactBackgroundDrawable); + final float topLeftBorderRadius = borderRadii[0]; + final float topRightBorderRadius = borderRadii[1]; + final float bottomRightBorderRadius = borderRadii[2]; + final float bottomLeftBorderRadius = borderRadii[3]; if (topLeftBorderRadius > 0 || topRightBorderRadius > 0 @@ -856,6 +803,97 @@ public class ReactViewGroup extends ViewGroup } } + @NonNull + private float[] getBorderRadii(@NonNull ReactViewBackgroundDrawable backgroundDrawable) { + final float borderRadius = backgroundDrawable.getFullBorderRadius(); + float topLeftBorderRadius = + backgroundDrawable.getBorderRadiusOrDefaultTo( + borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_LEFT); + float topRightBorderRadius = + backgroundDrawable.getBorderRadiusOrDefaultTo( + borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_RIGHT); + float bottomLeftBorderRadius = + backgroundDrawable.getBorderRadiusOrDefaultTo( + borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_LEFT); + float bottomRightBorderRadius = + backgroundDrawable.getBorderRadiusOrDefaultTo( + borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_RIGHT); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + final boolean isRTL = mLayoutDirection == View.LAYOUT_DIRECTION_RTL; + float topStartBorderRadius = + backgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_START); + float topEndBorderRadius = + backgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_END); + float bottomStartBorderRadius = + backgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_START); + float bottomEndBorderRadius = + backgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_END); + + if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(getContext())) { + if (YogaConstants.isUndefined(topStartBorderRadius)) { + topStartBorderRadius = topLeftBorderRadius; + } + + if (YogaConstants.isUndefined(topEndBorderRadius)) { + topEndBorderRadius = topRightBorderRadius; + } + + if (YogaConstants.isUndefined(bottomStartBorderRadius)) { + bottomStartBorderRadius = bottomLeftBorderRadius; + } + + if (YogaConstants.isUndefined(bottomEndBorderRadius)) { + bottomEndBorderRadius = bottomRightBorderRadius; + } + + final float directionAwareTopLeftRadius = isRTL ? topEndBorderRadius : topStartBorderRadius; + final float directionAwareTopRightRadius = + isRTL ? topStartBorderRadius : topEndBorderRadius; + final float directionAwareBottomLeftRadius = + isRTL ? bottomEndBorderRadius : bottomStartBorderRadius; + final float directionAwareBottomRightRadius = + isRTL ? bottomStartBorderRadius : bottomEndBorderRadius; + + topLeftBorderRadius = directionAwareTopLeftRadius; + topRightBorderRadius = directionAwareTopRightRadius; + bottomLeftBorderRadius = directionAwareBottomLeftRadius; + bottomRightBorderRadius = directionAwareBottomRightRadius; + } else { + final float directionAwareTopLeftRadius = isRTL ? topEndBorderRadius : topStartBorderRadius; + final float directionAwareTopRightRadius = + isRTL ? topStartBorderRadius : topEndBorderRadius; + final float directionAwareBottomLeftRadius = + isRTL ? bottomEndBorderRadius : bottomStartBorderRadius; + final float directionAwareBottomRightRadius = + isRTL ? bottomStartBorderRadius : bottomEndBorderRadius; + + if (!YogaConstants.isUndefined(directionAwareTopLeftRadius)) { + topLeftBorderRadius = directionAwareTopLeftRadius; + } + + if (!YogaConstants.isUndefined(directionAwareTopRightRadius)) { + topRightBorderRadius = directionAwareTopRightRadius; + } + + if (!YogaConstants.isUndefined(directionAwareBottomLeftRadius)) { + bottomLeftBorderRadius = directionAwareBottomLeftRadius; + } + + if (!YogaConstants.isUndefined(directionAwareBottomRightRadius)) { + bottomRightBorderRadius = directionAwareBottomRightRadius; + } + } + } + return new float[] { + topLeftBorderRadius, topRightBorderRadius, bottomRightBorderRadius, bottomLeftBorderRadius + }; + } + public void setOpacityIfPossible(float opacity) { mBackfaceOpacity = opacity; setBackfaceVisibilityDependantOpacity(); 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 7acaf8c48af..c1a88cdb24b 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 @@ -52,6 +52,9 @@ public class ReactViewManager extends ViewGroupManager { private static final int CMD_SET_PRESSED = 2; private static final String HOTSPOT_UPDATE_KEY = "hotspotUpdate"; + private @Nullable ReadableMap mNativeBackground; + private @Nullable ReadableMap mNativeForeground; + @ReactProp(name = "accessible") public void setAccessible(ReactViewGroup view, boolean accessible) { view.setFocusable(accessible); @@ -118,6 +121,14 @@ public class ReactViewManager extends ViewGroupManager { } else { view.setBorderRadius(borderRadius, index - 1); } + + if (mNativeBackground != null) { + setNativeBackground(view, mNativeBackground); + } + + if (mNativeForeground != null) { + setNativeForeground(view, mNativeForeground); + } } @ReactProp(name = "borderStyle") @@ -158,19 +169,17 @@ public class ReactViewManager extends ViewGroupManager { @ReactProp(name = "nativeBackgroundAndroid") public void setNativeBackground(ReactViewGroup view, @Nullable ReadableMap bg) { + mNativeBackground = bg; view.setTranslucentBackgroundDrawable( - bg == null - ? null - : ReactDrawableHelper.createDrawableFromJSDescription(view.getContext(), bg)); + bg == null ? null : ReactDrawableHelper.createDrawableFromJSDescription(view, bg)); } @TargetApi(Build.VERSION_CODES.M) @ReactProp(name = "nativeForegroundAndroid") public void setNativeForeground(ReactViewGroup view, @Nullable ReadableMap fg) { + mNativeForeground = fg; view.setForeground( - fg == null - ? null - : ReactDrawableHelper.createDrawableFromJSDescription(view.getContext(), fg)); + fg == null ? null : ReactDrawableHelper.createDrawableFromJSDescription(view, fg)); } @ReactProp(