Skip to content

Commit 4c83237

Browse files
janicduplessisFacebook Github Bot 6
authored and
Facebook Github Bot 6
committed
Add Image resizeMode repeat on iOS
Summary: This adds a new resize mode for iOS 'repeat' that tiles the image over it's frame. This allow to easily create a view with a repeating background pattern which there is no way to do at the moment without including a bunch of different sized assets. I'm not 100% sure it should be a resizeMode or a separate prop but I went with resizeMode since it made more sense to me and the are not really any use cases where we'd want to use this with another resizeMode other than 'stretch'. **Test plan** Tested mainly by adding a UIExplorer example, also tested that changing the resizeMode prop from and to 'repeat' worked properly. ![screen shot 2016-06-07 at 3 06 17 am](https://cloud.githubusercontent.com/assets/2677334/15848755/d95d8046-2c5c-11e6-9f3d-1ce8a1c9c846.png) I'd like to implement this on Android too but it is a bit trickier since Fresco's ImageView doesn't support image tiling and would require submitting a PR there too :( Closes #7968 Differential Revision: D3469119 Pulled By: javache fbshipit-source-id: ab9dbfe448a5b0771dbf0c41fcceeb366210f583
1 parent 0669a38 commit 4c83237

9 files changed

+48
-9
lines changed

Diff for: Examples/UIExplorer/ImageExample.js

+12
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,18 @@ exports.examples = [
505505
source={image}
506506
/>
507507
</View>
508+
{ Platform.OS === 'ios' ?
509+
<View style={styles.leftMargin}>
510+
<Text style={[styles.resizeModeText]}>
511+
Repeat
512+
</Text>
513+
<Image
514+
style={styles.resizeMode}
515+
resizeMode={Image.resizeMode.repeat}
516+
source={image}
517+
/>
518+
</View>
519+
: null }
508520
{ Platform.OS === 'android' ?
509521
<View style={styles.leftMargin}>
510522
<Text style={[styles.resizeModeText]}>

Diff for: Libraries/Image/Image.ios.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,11 @@ const Image = React.createClass({
126126
*
127127
* 'stretch': Scale width and height independently, This may change the
128128
* aspect ratio of the src.
129+
*
130+
* 'repeat': Repeat the image to cover the frame of the view. The
131+
* image will keep it's size and aspect ratio. (iOS only)
129132
*/
130-
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
133+
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat']),
131134
/**
132135
* A unique identifier for this element to be used in UI Automation
133136
* testing scripts.

Diff for: Libraries/Image/ImageResizeMode.js

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ var ImageResizeMode = keyMirror({
4040
* The image will not be scaled up.
4141
*/
4242
center: null,
43+
44+
/**
45+
* repeat - The image will be repeated to cover the frame of the View. The
46+
* image will keep it's size and aspect ratio.
47+
*/
48+
repeat: null,
4349
});
4450

4551
module.exports = ImageResizeMode;

Diff for: Libraries/Image/RCTImageUtils.m

+5
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
6464

6565
switch (resizeMode) {
6666
case RCTResizeModeStretch:
67+
case RCTResizeModeRepeat:
6768

6869
return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
6970

@@ -204,6 +205,10 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
204205

205206
return destSize.width > sourceSize.width;
206207
}
208+
209+
case RCTResizeModeRepeat:
210+
211+
return NO;
207212
}
208213
}
209214

Diff for: Libraries/Image/RCTImageView.h

+1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
@property (nonatomic, assign) UIImageRenderingMode renderingMode;
2323
@property (nonatomic, strong) RCTImageSource *source;
2424
@property (nonatomic, assign) CGFloat blurRadius;
25+
@property (nonatomic, assign) RCTResizeMode resizeMode;
2526

2627
@end

Diff for: Libraries/Image/RCTImageView.m

+17-7
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,12 @@ - (void)updateImage
9595
image = [image imageWithRenderingMode:_renderingMode];
9696
}
9797

98-
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
99-
if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
98+
if (_resizeMode == RCTResizeModeRepeat) {
99+
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeTile];
100+
} else if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
101+
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
100102
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeStretch];
101103
}
102-
103104
// Apply trilinear filtering to smooth out mis-sized images
104105
self.layer.minificationFilter = kCAFilterTrilinear;
105106
self.layer.magnificationFilter = kCAFilterTrilinear;
@@ -161,10 +162,19 @@ - (BOOL)sourceNeedsReload
161162
return UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero);
162163
}
163164

164-
- (void)setContentMode:(UIViewContentMode)contentMode
165+
- (void)setResizeMode:(RCTResizeMode)resizeMode
165166
{
166-
if (self.contentMode != contentMode) {
167-
super.contentMode = contentMode;
167+
if (_resizeMode != resizeMode) {
168+
_resizeMode = resizeMode;
169+
170+
if (_resizeMode == RCTResizeModeRepeat) {
171+
// Repeat resize mode is handled by the UIImage. Use scale to fill
172+
// so the repeated image fills the UIImageView.
173+
self.contentMode = UIViewContentModeScaleToFill;
174+
} else {
175+
self.contentMode = (UIViewContentMode)resizeMode;
176+
}
177+
168178
if ([self sourceNeedsReload]) {
169179
[self reloadImage];
170180
}
@@ -229,7 +239,7 @@ - (void)reloadImage
229239
size:imageSize
230240
scale:imageScale
231241
clipped:NO
232-
resizeMode:(RCTResizeMode)self.contentMode
242+
resizeMode:_resizeMode
233243
progressBlock:progressHandler
234244
completionBlock:^(NSError *error, UIImage *loadedImage) {
235245

Diff for: Libraries/Image/RCTImageViewManager.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ - (UIView *)view
3333
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
3434
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
3535
RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
36-
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, RCTResizeMode)
36+
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
3737
RCT_EXPORT_VIEW_PROPERTY(source, RCTImageSource)
3838
RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
3939
{

Diff for: Libraries/Image/RCTResizeMode.h

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ typedef NS_ENUM(NSInteger, RCTResizeMode) {
1313
RCTResizeModeCover = UIViewContentModeScaleAspectFill,
1414
RCTResizeModeContain = UIViewContentModeScaleAspectFit,
1515
RCTResizeModeStretch = UIViewContentModeScaleToFill,
16+
RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values.
1617
};
1718

1819
@interface RCTConvert(RCTResizeMode)

Diff for: Libraries/Image/RCTResizeMode.m

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ @implementation RCTConvert(RCTResizeMode)
1515
@"cover": @(RCTResizeModeCover),
1616
@"contain": @(RCTResizeModeContain),
1717
@"stretch": @(RCTResizeModeStretch),
18+
@"repeat": @(RCTResizeModeRepeat),
1819
}), RCTResizeModeStretch, integerValue)
1920

2021
@end

0 commit comments

Comments
 (0)