Skip to content

Commit b2452ab

Browse files
gedeagasfacebook-github-bot
authored andcommitted
feat: Adding support for objectFit a partial equivalent to the resizeMode style and prop of <Image>. (#34576)
Summary: This PR aims to add support for objectFit a partial equivalent to the resizeMode style and prop of Image. ## Changelog [General] [Added] - Add support for objectFit style of Image. Pull Request resolved: #34576 Test Plan: 1. Open the RNTester app and navigate to the Image page 2. See the Object Fit section. ![Screenshot_1662112702](https://user-images.githubusercontent.com/8868908/188115315-5d5aa971-93ba-4437-a54b-c5ea69b00c08.png) Reviewed By: rickhanlonii Differential Revision: D39261176 Pulled By: jacdebug fbshipit-source-id: 1eefd76b6c11ed5fc52b2c524ad78c91051077f6
1 parent 4d04b1d commit b2452ab

File tree

6 files changed

+100
-4
lines changed

6 files changed

+100
-4
lines changed

Libraries/Components/View/ReactNativeStyleAttributes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
143143
overlayColor: colorAttributes,
144144
resizeMode: true,
145145
tintColor: colorAttributes,
146+
objectFit: true,
146147
};
147148

148149
module.exports = ReactNativeStyleAttributes;

Libraries/Image/Image.android.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import NativeImageLoaderAndroid from './NativeImageLoaderAndroid';
2121

2222
import TextInlineImageNativeComponent from './TextInlineImageNativeComponent';
2323

24+
import {convertObjectFitToResizeMode} from './ImageUtils';
25+
2426
import type {ImageProps as ImagePropsType} from './ImageProps';
2527
import type {RootTag} from '../Types/RootTagTypes';
2628
import {getImageSourcesFromImageProps} from './ImageSourceUtils';
@@ -187,6 +189,14 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => {
187189
},
188190
};
189191

192+
const objectFit =
193+
style && style.objectFit
194+
? convertObjectFitToResizeMode(style.objectFit)
195+
: null;
196+
// $FlowFixMe[prop-missing]
197+
const resizeMode =
198+
objectFit || props.resizeMode || (style && style.resizeMode) || 'cover';
199+
190200
return (
191201
<ImageAnalyticsTagContext.Consumer>
192202
{analyticTag => {
@@ -205,15 +215,20 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => {
205215
return (
206216
<TextInlineImageNativeComponent
207217
style={style}
208-
resizeMode={props.resizeMode}
218+
resizeMode={resizeMode}
209219
headers={nativeProps.headers}
210220
src={src}
211221
ref={forwardedRef}
212222
/>
213223
);
214224
}
215225

216-
return <ImageViewNativeComponent {...nativePropsWithAnalytics} />;
226+
return (
227+
<ImageViewNativeComponent
228+
{...nativePropsWithAnalytics}
229+
resizeMode={resizeMode}
230+
/>
231+
);
217232
}}
218233
</TextAncestor.Consumer>
219234
);

Libraries/Image/Image.ios.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import type {ImageProps as ImagePropsType} from './ImageProps';
2121
import type {ImageStyleProp} from '../StyleSheet/StyleSheet';
2222
import NativeImageLoaderIOS from './NativeImageLoaderIOS';
2323

24+
import {convertObjectFitToResizeMode} from './ImageUtils';
25+
2426
import ImageViewNativeComponent from './ImageViewNativeComponent';
2527
import type {RootTag} from 'react-native/Libraries/Types/RootTagTypes';
2628
import {getImageSourcesFromImageProps} from './ImageSourceUtils';
@@ -127,8 +129,14 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => {
127129
}
128130
}
129131

130-
// $FlowFixMe[prop-missing]
131-
const resizeMode = props.resizeMode || style.resizeMode || 'cover';
132+
const objectFit =
133+
// $FlowFixMe[prop-missing]
134+
style && style.objectFit
135+
? convertObjectFitToResizeMode(style.objectFit)
136+
: null;
137+
const resizeMode =
138+
// $FlowFixMe[prop-missing]
139+
objectFit || props.resizeMode || (style && style.resizeMode) || 'cover';
132140
// $FlowFixMe[prop-missing]
133141
const tintColor = props.tintColor || style.tintColor;
134142

Libraries/Image/ImageUtils.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
* @format
9+
*/
10+
11+
type ResizeMode = 'cover' | 'contain' | 'stretch' | 'repeat' | 'center';
12+
13+
export function convertObjectFitToResizeMode(objectFit: string): ResizeMode {
14+
const objectFitMap = {
15+
contain: 'contain',
16+
cover: 'cover',
17+
fill: 'stretch',
18+
'scale-down': 'contain',
19+
};
20+
return objectFitMap[objectFit];
21+
}

Libraries/StyleSheet/StyleSheetTypes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ export type ____TextStyle_Internal = $ReadOnly<{
644644
export type ____ImageStyle_InternalCore = $ReadOnly<{
645645
...$Exact<____ViewStyle_Internal>,
646646
resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
647+
objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down',
647648
tintColor?: ____ColorValue_Internal,
648649
overlayColor?: string,
649650
}>;
@@ -656,6 +657,7 @@ export type ____ImageStyle_Internal = $ReadOnly<{
656657
export type ____DangerouslyImpreciseStyle_InternalCore = $ReadOnly<{
657658
...$Exact<____TextStyle_Internal>,
658659
resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
660+
objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down',
659661
tintColor?: ____ColorValue_Internal,
660662
overlayColor?: string,
661663
}>;

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,55 @@ exports.examples = [
10611061
);
10621062
},
10631063
},
1064+
{
1065+
title: 'Object Fit',
1066+
description: ('The `objectFit` style prop controls how the image is ' +
1067+
'rendered within the frame.': string),
1068+
render: function (): React.Node {
1069+
return (
1070+
<View>
1071+
{[smallImage, fullImage].map((image, index) => {
1072+
return (
1073+
<View key={index}>
1074+
<View style={styles.horizontal}>
1075+
<View>
1076+
<Text style={styles.resizeModeText}>Contain</Text>
1077+
<Image
1078+
style={[styles.resizeMode, {objectFit: 'contain'}]}
1079+
source={image}
1080+
/>
1081+
</View>
1082+
<View style={styles.leftMargin}>
1083+
<Text style={styles.resizeModeText}>Cover</Text>
1084+
<Image
1085+
style={[styles.resizeMode, {objectFit: 'cover'}]}
1086+
source={image}
1087+
/>
1088+
</View>
1089+
</View>
1090+
<View style={styles.horizontal}>
1091+
<View>
1092+
<Text style={styles.resizeModeText}>Fill</Text>
1093+
<Image
1094+
style={[styles.resizeMode, {objectFit: 'fill'}]}
1095+
source={image}
1096+
/>
1097+
</View>
1098+
<View style={styles.leftMargin}>
1099+
<Text style={styles.resizeModeText}>Scale Down</Text>
1100+
<Image
1101+
style={[styles.resizeMode, {objectFit: 'scale-down'}]}
1102+
source={image}
1103+
/>
1104+
</View>
1105+
</View>
1106+
</View>
1107+
);
1108+
})}
1109+
</View>
1110+
);
1111+
},
1112+
},
10641113
{
10651114
title: 'Resize Mode',
10661115
description: ('The `resizeMode` style prop controls how the image is ' +

0 commit comments

Comments
 (0)