diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt index 50724f23a6f..3a16760c809 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt @@ -105,13 +105,14 @@ public object BackgroundStyleApplicator { ): Unit { ensureCSSBackground(view).setBorderRadius(corner, radius) val compositeBackgroundDrawable = ensureCompositeBackgroundDrawable(view) + compositeBackgroundDrawable.borderRadius = + compositeBackgroundDrawable.borderRadius ?: BorderRadiusStyle() + compositeBackgroundDrawable.borderRadius?.set(corner, radius) if (Build.VERSION.SDK_INT >= MIN_OUTSET_BOX_SHADOW_SDK_VERSION) { for (shadow in compositeBackgroundDrawable.outerShadows) { if (shadow is OutsetBoxShadowDrawable) { - shadow.borderRadius = shadow.borderRadius ?: BorderRadiusStyle() - shadow.borderRadius?.set(corner, radius) - shadow.invalidateSelf() + shadow.borderRadius = compositeBackgroundDrawable.borderRadius } } } @@ -119,19 +120,13 @@ public object BackgroundStyleApplicator { if (Build.VERSION.SDK_INT >= MIN_INSET_BOX_SHADOW_SDK_VERSION) { for (shadow in compositeBackgroundDrawable.innerShadows) { if (shadow is InsetBoxShadowDrawable) { - shadow.borderRadius = shadow.borderRadius ?: BorderRadiusStyle() - shadow.borderRadius?.set(corner, radius) - shadow.invalidateSelf() + shadow.borderRadius = compositeBackgroundDrawable.borderRadius } } } - val outline = compositeBackgroundDrawable.outline - if (outline != null) { - outline.borderRadius = outline.borderRadius ?: BorderRadiusStyle() - outline.borderRadius?.set(corner, radius) - outline.invalidateSelf() - } + compositeBackgroundDrawable.outline?.borderRadius = compositeBackgroundDrawable.borderRadius + compositeBackgroundDrawable.invalidateSelf() } @JvmStatic @@ -207,7 +202,9 @@ public object BackgroundStyleApplicator { val outerShadows = mutableListOf() val innerShadows = mutableListOf() - val borderInsets = ensureCompositeBackgroundDrawable(view).borderInsets + val compositeBackgroundDrawable = ensureCompositeBackgroundDrawable(view) + val borderInsets = compositeBackgroundDrawable.borderInsets + val borderRadius = compositeBackgroundDrawable.borderRadius for (boxShadow in shadows) { val offsetX = boxShadow.offsetX @@ -221,7 +218,7 @@ public object BackgroundStyleApplicator { innerShadows.add( InsetBoxShadowDrawable( context = view.context, - borderRadius = ensureCSSBackground(view).borderRadius, + borderRadius = borderRadius, borderInsets = borderInsets, shadowColor = color, offsetX = offsetX, @@ -232,7 +229,7 @@ public object BackgroundStyleApplicator { outerShadows.add( OutsetBoxShadowDrawable( context = view.context, - borderRadius = ensureCSSBackground(view).borderRadius, + borderRadius = borderRadius, shadowColor = color, offsetX = offsetX, offsetY = offsetY, @@ -329,7 +326,7 @@ public object BackgroundStyleApplicator { outline = OutlineDrawable( context = view.context, - borderRadius = ensureCSSBackground(view).borderRadius.copy(), + borderRadius = compositeBackgroundDrawable.borderRadius, outlineColor = Color.BLACK, outlineOffset = 0f, outlineStyle = OutlineStyle.SOLID, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt index adf57cc7c53..a3d2d639846 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt @@ -11,6 +11,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.uimanager.style.BorderInsets +import com.facebook.react.uimanager.style.BorderRadiusStyle /** * CompositeBackgroundDrawable can overlay multiple different layers, shadows, and native effects @@ -59,6 +60,8 @@ internal class CompositeBackgroundDrawable( // Holder value for currently set insets public var borderInsets: BorderInsets? = null + // Holder value for currently set border radius + public var borderRadius: BorderRadiusStyle? = null init { // We want to overlay drawables, instead of placing future drawables within the content area of @@ -71,7 +74,16 @@ internal class CompositeBackgroundDrawable( cssBackground: CSSBackgroundDrawable? ): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, feedbackUnderlay, innerShadows, outline) + originalBackground, + outerShadows, + cssBackground, + feedbackUnderlay, + innerShadows, + outline) + .also { composite -> + composite.borderInsets = this.borderInsets + composite.borderRadius = this.borderRadius + } } public fun withNewShadows( @@ -79,16 +91,38 @@ internal class CompositeBackgroundDrawable( innerShadows: List ): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, feedbackUnderlay, innerShadows, outline) + originalBackground, + outerShadows, + cssBackground, + feedbackUnderlay, + innerShadows, + outline) + .also { composite -> + composite.borderInsets = this.borderInsets + composite.borderRadius = this.borderRadius + } } public fun withNewOutline(outline: OutlineDrawable): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, feedbackUnderlay, innerShadows, outline) + originalBackground, + outerShadows, + cssBackground, + feedbackUnderlay, + innerShadows, + outline) + .also { composite -> + composite.borderInsets = this.borderInsets + composite.borderRadius = this.borderRadius + } } public fun withNewFeedbackUnderlay(newUnderlay: Drawable?): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, newUnderlay, innerShadows, outline) + originalBackground, outerShadows, cssBackground, newUnderlay, innerShadows, outline) + .apply { + borderInsets = this@CompositeBackgroundDrawable.borderInsets + borderRadius = this@CompositeBackgroundDrawable.borderRadius + } } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt index a241468a714..1910cdff8a5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt @@ -40,30 +40,18 @@ private val ZERO_RADII = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f) @RequiresApi(MIN_INSET_BOX_SHADOW_SDK_VERSION) internal class InsetBoxShadowDrawable( private val context: Context, - borderRadius: BorderRadiusStyle? = null, - borderInsets: BorderInsets? = null, private val shadowColor: Int, private val offsetX: Float, private val offsetY: Float, private val blurRadius: Float, private val spread: Float, + /* + * We assume borderRadius & borderInsets to be shared across multiple drawables + * therefore user should invalidate this drawable when changing either of them + */ + var borderInsets: BorderInsets? = null, + var borderRadius: BorderRadiusStyle? = null, ) : Drawable() { - public var borderRadius = borderRadius - set(value) { - if (value != field) { - field = value - invalidateSelf() - } - } - - public var borderInsets = borderInsets - set(value) { - if (value != field) { - field = value - invalidateSelf() - } - } - private val shadowPaint = Paint().apply { color = shadowColor diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt index 7e0454a2cfa..b8d3eeee07c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt @@ -23,14 +23,15 @@ import com.facebook.react.uimanager.style.ComputedBorderRadius import com.facebook.react.uimanager.style.CornerRadii import com.facebook.react.uimanager.style.OutlineStyle import kotlin.math.roundToInt -import kotlin.properties.ObservableProperty -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty /** Draws outline https://drafts.csswg.org/css-ui/#outline */ internal class OutlineDrawable( private val context: Context, - borderRadius: BorderRadiusStyle? = null, + /* + * We assume borderRadius to be shared across multiple drawables + * therefore we should manually invalidate this drawable when changing it + */ + var borderRadius: BorderRadiusStyle? = null, outlineColor: Int, outlineOffset: Float, outlineStyle: OutlineStyle, @@ -43,17 +44,14 @@ internal class OutlineDrawable( */ private val gapBetweenPaths = 0.8f - private fun invalidatingChange(initialValue: T): ReadWriteProperty = - object : ObservableProperty(initialValue) { - override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) { - if (oldValue != newValue) { - invalidateSelf() - } - } + public var outlineOffset: Float = outlineOffset + set(value) { + if (value != field) { + field = value + invalidateSelf() } + } - public var borderRadius: BorderRadiusStyle? by invalidatingChange(borderRadius) - public var outlineOffset: Float by invalidatingChange(outlineOffset) public var outlineStyle: OutlineStyle = outlineStyle set(value) { if (value != field) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt index 3d4a433d908..1cab38b5905 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt @@ -37,21 +37,17 @@ private const val BLUR_RADIUS_SIGMA_SCALE = 0.5f @RequiresApi(MIN_OUTSET_BOX_SHADOW_SDK_VERSION) internal class OutsetBoxShadowDrawable( private val context: Context, - borderRadius: BorderRadiusStyle? = null, private val shadowColor: Int, private val offsetX: Float, private val offsetY: Float, private val blurRadius: Float, private val spread: Float, + /* + * We assume borderRadius to be shared across multiple drawables + * therefore we should manually invalidate this drawable when changing it + */ + var borderRadius: BorderRadiusStyle? = null, ) : Drawable() { - public var borderRadius = borderRadius - set(value) { - if (value != field) { - field = value - invalidateSelf() - } - } - private val shadowPaint = Paint().apply { color = shadowColor