Skip to content

Commit 17d1d2a

Browse files
sbaiahmed1claude
andcommitted
Fix crash when setting a percentage borderRadius on Image (Android)
Percentage border radii arrive from JS as strings ('50%'), but ReactImageManager's borderRadius @ReactPropGroup setter still typed the prop as Float, so the reflection-based property updater crashed with "java.lang.String cannot be cast to java.lang.Double" under the new architecture. Accept a Dynamic and parse it with LengthPercentage.setFromDynamic, mirroring the migration ReactViewManager received in 0.75. The Float overload is kept as a deprecated pass-through for backward compatibility. Rendering needs no changes since the manager already delegates to BackgroundStyleApplicator, which resolves percentages. Fixes #53977 Changelog: [ANDROID] [FIXED] - Fix crash when setting a percentage borderRadius on Image Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jdkybd1fVVGHCFk2EF2Q1
1 parent 63e9c15 commit 17d1d2a

4 files changed

Lines changed: 51 additions & 6 deletions

File tree

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5312,6 +5312,7 @@ public final class com/facebook/react/views/image/ReactImageManager : com/facebo
53125312
public final fun setBlurRadius (Lcom/facebook/react/views/image/ReactImageView;F)V
53135313
public final fun setBorderColor (Lcom/facebook/react/views/image/ReactImageView;Ljava/lang/Integer;)V
53145314
public final fun setBorderRadius (Lcom/facebook/react/views/image/ReactImageView;IF)V
5315+
public final fun setBorderRadius (Lcom/facebook/react/views/image/ReactImageView;ILcom/facebook/react/bridge/Dynamic;)V
53155316
public final fun setBorderWidth (Lcom/facebook/react/views/image/ReactImageView;F)V
53165317
public final fun setDefaultSource (Lcom/facebook/react/views/image/ReactImageView;Ljava/lang/String;)V
53175318
public final fun setFadeDuration (Lcom/facebook/react/views/image/ReactImageView;I)V

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.kt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ import android.graphics.PorterDuff
1212
import com.facebook.common.logging.FLog
1313
import com.facebook.drawee.backends.pipeline.Fresco
1414
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder
15+
import com.facebook.react.bridge.Dynamic
16+
import com.facebook.react.bridge.DynamicFromObject
1517
import com.facebook.react.bridge.ReadableArray
1618
import com.facebook.react.bridge.ReadableMap
1719
import com.facebook.react.common.ReactConstants
1820
import com.facebook.react.module.annotations.ReactModule
1921
import com.facebook.react.uimanager.BackgroundStyleApplicator
2022
import com.facebook.react.uimanager.LengthPercentage
21-
import com.facebook.react.uimanager.LengthPercentageType
2223
import com.facebook.react.uimanager.SimpleViewManager
2324
import com.facebook.react.uimanager.ThemedReactContext
2425
import com.facebook.react.uimanager.ViewProps
@@ -171,13 +172,18 @@ public constructor(
171172
ViewProps.BORDER_BOTTOM_RIGHT_RADIUS,
172173
ViewProps.BORDER_BOTTOM_LEFT_RADIUS,
173174
],
174-
defaultFloat = Float.NaN,
175+
)
176+
public fun setBorderRadius(view: ReactImageView, index: Int, rawBorderRadius: Dynamic) {
177+
val borderRadius = LengthPercentage.setFromDynamic(rawBorderRadius)
178+
BackgroundStyleApplicator.setBorderRadius(view, BorderRadiusProp.values()[index], borderRadius)
179+
}
180+
181+
@Deprecated(
182+
"Don't use setBorderRadius(view, index, Float) as it was deprecated in React Native 0.87.0.",
183+
ReplaceWith("setBorderRadius(view, index, DynamicFromObject(borderRadius))"),
175184
)
176185
public fun setBorderRadius(view: ReactImageView, index: Int, borderRadius: Float) {
177-
val radius =
178-
if (borderRadius.isNaN()) null
179-
else LengthPercentage(borderRadius, LengthPercentageType.POINT)
180-
BackgroundStyleApplicator.setBorderRadius(view, BorderRadiusProp.values()[index], radius)
186+
setBorderRadius(view, index, DynamicFromObject(borderRadius))
181187
}
182188

183189
@ReactProp(name = ViewProps.RESIZE_MODE)

packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@ import com.facebook.react.bridge.JavaOnlyMap
2323
import com.facebook.react.bridge.ReactTestHelper.createMockCatalystInstance
2424
import com.facebook.react.common.ReactConstants
2525
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsForTests
26+
import com.facebook.react.uimanager.BackgroundStyleApplicator
2627
import com.facebook.react.uimanager.DisplayMetricsHolder
28+
import com.facebook.react.uimanager.LengthPercentage
29+
import com.facebook.react.uimanager.LengthPercentageType
2730
import com.facebook.react.uimanager.ReactStylesDiffMap
2831
import com.facebook.react.uimanager.ThemedReactContext
32+
import com.facebook.react.uimanager.style.BorderRadiusProp
2933
import com.facebook.react.util.RNLog
3034
import com.facebook.react.views.imagehelper.ImageSource
3135
import com.facebook.soloader.SoLoader
@@ -142,6 +146,31 @@ class ReactImagePropertyTest {
142146
.isEqualTo(view.imageSource)
143147
}
144148

149+
@Test
150+
fun testBorderRadius() {
151+
val viewManager = ReactImageManager()
152+
val view = viewManager.createViewInstance(themeContext)
153+
154+
// Percentage border radii arrive as strings and must not crash the property updater
155+
viewManager.updateProperties(view, buildStyles("borderRadius", "50%"))
156+
assertThat(BackgroundStyleApplicator.getBorderRadius(view, BorderRadiusProp.BORDER_RADIUS))
157+
.isEqualTo(LengthPercentage(50f, LengthPercentageType.PERCENT))
158+
159+
viewManager.updateProperties(view, buildStyles("borderRadius", 10.0))
160+
assertThat(BackgroundStyleApplicator.getBorderRadius(view, BorderRadiusProp.BORDER_RADIUS))
161+
.isEqualTo(LengthPercentage(10f, LengthPercentageType.POINT))
162+
163+
viewManager.updateProperties(view, buildStyles("borderTopLeftRadius", "25%"))
164+
assertThat(
165+
BackgroundStyleApplicator.getBorderRadius(view, BorderRadiusProp.BORDER_TOP_LEFT_RADIUS)
166+
)
167+
.isEqualTo(LengthPercentage(25f, LengthPercentageType.PERCENT))
168+
169+
viewManager.updateProperties(view, buildStyles("borderRadius", null))
170+
assertThat(BackgroundStyleApplicator.getBorderRadius(view, BorderRadiusProp.BORDER_RADIUS))
171+
.isNull()
172+
}
173+
145174
@Test
146175
fun testResizeMode() {
147176
val viewManager = ReactImageManager()

packages/rn-tester/js/examples/Image/ImageExample.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,11 @@ const styles = StyleSheet.create({
11861186
borderColor: 'red',
11871187
backgroundColor: 'yellow',
11881188
},
1189+
borderRadiusPercentage: {
1190+
borderWidth: 4,
1191+
borderRadius: '50%',
1192+
borderColor: 'green',
1193+
},
11891194
boxShadow: {
11901195
margin: 10,
11911196
},
@@ -1448,6 +1453,10 @@ exports.examples = [
14481453
style={[styles.base, styles.borderRadius5]}
14491454
source={fullImage}
14501455
/>
1456+
<Image
1457+
style={[styles.base, styles.borderRadiusPercentage]}
1458+
source={fullImage}
1459+
/>
14511460
</View>
14521461
);
14531462
},

0 commit comments

Comments
 (0)