Skip to content

Commit c7075c3

Browse files
add background size cover and contain
1 parent 13240f1 commit c7075c3

File tree

4 files changed

+101
-7
lines changed

4 files changed

+101
-7
lines changed

packages/react-native/React/Fabric/Utils/RCTBackgroundImageUtils.mm

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,23 @@ + (CGSize)calculateBackgroundImageSize:(const CGRect &)positioningArea
160160
CGSize itemFinalSize = itemIntrinsicSize;
161161
CGSize positioningAreaSize = positioningArea.size;
162162

163-
if (std::holds_alternative<facebook::react::BackgroundSizeLengthPercentage>(backgroundSize)) {
163+
if (std::holds_alternative<facebook::react::BackgroundSizeKeyword>(backgroundSize)) {
164+
auto keyword = std::get<facebook::react::BackgroundSizeKeyword>(backgroundSize);
165+
if (itemIntrinsicSize.width > 0 && itemIntrinsicSize.height > 0) {
166+
CGFloat scaleX = positioningAreaSize.width / itemIntrinsicSize.width;
167+
CGFloat scaleY = positioningAreaSize.height / itemIntrinsicSize.height;
168+
169+
if (keyword == facebook::react::BackgroundSizeKeyword::Cover) {
170+
CGFloat scale = std::max(scaleX, scaleY);
171+
itemFinalSize.width = itemIntrinsicSize.width * scale;
172+
itemFinalSize.height = itemIntrinsicSize.height * scale;
173+
} else if (keyword == facebook::react::BackgroundSizeKeyword::Contain) {
174+
CGFloat scale = std::min(scaleX, scaleY);
175+
itemFinalSize.width = itemIntrinsicSize.width * scale;
176+
itemFinalSize.height = itemIntrinsicSize.height * scale;
177+
}
178+
}
179+
} else if (std::holds_alternative<facebook::react::BackgroundSizeLengthPercentage>(backgroundSize)) {
164180
auto backgroundSizeLengthPercentage = std::get<facebook::react::BackgroundSizeLengthPercentage>(backgroundSize);
165181
if (std::holds_alternative<facebook::react::ValueUnit>(backgroundSizeLengthPercentage.x)) {
166182
auto xValue = std::get<facebook::react::ValueUnit>(backgroundSizeLengthPercentage.x);

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BackgroundImageDrawable.kt

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,35 @@ internal class BackgroundImageDrawable(
383383
var finalWidth = imageWidth
384384
var finalHeight = imageHeight
385385

386-
if (backgroundSize is BackgroundSize.LengthPercentageAuto) {
387-
val w = backgroundSize.lengthPercentage.x
388-
val h = backgroundSize.lengthPercentage.y
389-
if (w != null && h != null) {
390-
finalWidth = positionToPixels(w, containerWidth)
391-
finalHeight = positionToPixels(h, containerHeight)
386+
when (backgroundSize) {
387+
is BackgroundSize.Cover -> {
388+
if (imageWidth > 0 && imageHeight > 0) {
389+
val scaleX = containerWidth / imageWidth
390+
val scaleY = containerHeight / imageHeight
391+
val scale = maxOf(scaleX, scaleY)
392+
finalWidth = imageWidth * scale
393+
finalHeight = imageHeight * scale
394+
}
395+
}
396+
is BackgroundSize.Contain -> {
397+
if (imageWidth > 0 && imageHeight > 0) {
398+
val scaleX = containerWidth / imageWidth
399+
val scaleY = containerHeight / imageHeight
400+
val scale = minOf(scaleX, scaleY)
401+
finalWidth = imageWidth * scale
402+
finalHeight = imageHeight * scale
403+
}
404+
}
405+
is BackgroundSize.LengthPercentageAuto -> {
406+
val w = backgroundSize.lengthPercentage.x
407+
val h = backgroundSize.lengthPercentage.y
408+
if (w != null && h != null) {
409+
finalWidth = positionToPixels(w, containerWidth)
410+
finalHeight = positionToPixels(h, containerHeight)
411+
}
412+
}
413+
null -> {
414+
// Keep intrinsic size
392415
}
393416
}
394417

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/BackgroundSize.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ internal class BackgroundSizeLengthPercentage(
7979
}
8080

8181
internal sealed class BackgroundSize {
82+
public data object Cover : BackgroundSize()
83+
84+
public data object Contain : BackgroundSize()
85+
8286
public class LengthPercentageAuto(public val lengthPercentage: BackgroundSizeLengthPercentage) :
8387
BackgroundSize()
8488

@@ -87,6 +91,13 @@ internal sealed class BackgroundSize {
8791
if (backgroundSizeValue == null) return null
8892

8993
return when (backgroundSizeValue.type) {
94+
ReadableType.String -> {
95+
when (backgroundSizeValue.asString()) {
96+
"cover" -> Cover
97+
"contain" -> Contain
98+
else -> null
99+
}
100+
}
90101
ReadableType.Map -> {
91102
val backgroundSizeValueMap = backgroundSizeValue.asMap() ?: return null
92103
val lengthPercentage = BackgroundSizeLengthPercentage.parse(backgroundSizeValueMap)

packages/rn-tester/js/examples/BackgroundImage/BackgroundImageExample.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,4 +499,48 @@ exports.examples = [
499499
);
500500
},
501501
},
502+
{
503+
title: 'Background Size Cover and Contain',
504+
description:
505+
'Cover scales the image to completely cover the container. Contain scales to fit entirely within the container',
506+
name: 'size-cover-contain',
507+
render(): React.Node {
508+
return (
509+
<View style={styles.row}>
510+
<View style={styles.col}>
511+
<Text>cover</Text>
512+
<BackgroundImageBox
513+
style={{
514+
width: 150,
515+
height: 200,
516+
experimental_backgroundImage:
517+
'url(https://reactnative.dev/img/tiny_logo.png)',
518+
experimental_backgroundSize: 'cover',
519+
experimental_backgroundPosition: 'center',
520+
borderWidth: 1,
521+
borderColor: '#ccc',
522+
}}
523+
testID="background-image-size-cover"
524+
/>
525+
</View>
526+
<View style={styles.col}>
527+
<Text>contain</Text>
528+
<BackgroundImageBox
529+
style={{
530+
width: 150,
531+
height: 200,
532+
experimental_backgroundImage:
533+
'url(https://reactnative.dev/img/tiny_logo.png)',
534+
experimental_backgroundSize: 'contain',
535+
experimental_backgroundPosition: 'center',
536+
borderWidth: 1,
537+
borderColor: '#ccc',
538+
}}
539+
testID="background-image-size-contain"
540+
/>
541+
</View>
542+
</View>
543+
);
544+
},
545+
},
502546
] as Array<RNTesterModuleExample>;

0 commit comments

Comments
 (0)