Skip to content

Commit

Permalink
Add Image resizeMode repeat on iOS
Browse files Browse the repository at this point in the history
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 facebook#7968

Differential Revision: D3469119

Pulled By: javache

fbshipit-source-id: ab9dbfe448a5b0771dbf0c41fcceeb366210f583
  • Loading branch information
janicduplessis authored and Morgan Pretty committed Aug 24, 2016
1 parent 2aae03e commit 24879cd
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 9 deletions.
12 changes: 12 additions & 0 deletions Examples/UIExplorer/ImageExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,18 @@ exports.examples = [
source={image}
/>
</View>
{ Platform.OS === 'ios' ?
<View style={styles.leftMargin}>
<Text style={[styles.resizeModeText]}>
Repeat
</Text>
<Image
style={styles.resizeMode}
resizeMode={Image.resizeMode.repeat}
source={image}
/>
</View>
: null }
{ Platform.OS === 'android' ?
<View style={styles.leftMargin}>
<Text style={[styles.resizeModeText]}>
Expand Down
5 changes: 4 additions & 1 deletion Libraries/Image/Image.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,11 @@ const Image = React.createClass({
*
* 'stretch': Scale width and height independently, This may change the
* aspect ratio of the src.
*
* 'repeat': Repeat the image to cover the frame of the view. The
* image will keep it's size and aspect ratio. (iOS only)
*/
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat']),
/**
* A unique identifier for this element to be used in UI Automation
* testing scripts.
Expand Down
6 changes: 6 additions & 0 deletions Libraries/Image/ImageResizeMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ var ImageResizeMode = keyMirror({
* The image will not be scaled up.
*/
center: null,

/**
* repeat - The image will be repeated to cover the frame of the View. The
* image will keep it's size and aspect ratio.
*/
repeat: null,
});

module.exports = ImageResizeMode;
5 changes: 5 additions & 0 deletions Libraries/Image/RCTImageUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,

switch (resizeMode) {
case RCTResizeModeStretch:
case RCTResizeModeRepeat:

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

Expand Down Expand Up @@ -204,6 +205,10 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,

return destSize.width > sourceSize.width;
}

case RCTResizeModeRepeat:

return NO;
}
}

Expand Down
1 change: 1 addition & 0 deletions Libraries/Image/RCTImageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
@property (nonatomic, assign) UIImageRenderingMode renderingMode;
@property (nonatomic, strong) RCTImageSource *source;
@property (nonatomic, assign) CGFloat blurRadius;
@property (nonatomic, assign) RCTResizeMode resizeMode;

@end
24 changes: 17 additions & 7 deletions Libraries/Image/RCTImageView.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,12 @@ - (void)updateImage
image = [image imageWithRenderingMode:_renderingMode];
}

// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
if (_resizeMode == RCTResizeModeRepeat) {
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeTile];
} else if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeStretch];
}

// Apply trilinear filtering to smooth out mis-sized images
self.layer.minificationFilter = kCAFilterTrilinear;
self.layer.magnificationFilter = kCAFilterTrilinear;
Expand Down Expand Up @@ -161,10 +162,19 @@ - (BOOL)sourceNeedsReload
return UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero);
}

- (void)setContentMode:(UIViewContentMode)contentMode
- (void)setResizeMode:(RCTResizeMode)resizeMode
{
if (self.contentMode != contentMode) {
super.contentMode = contentMode;
if (_resizeMode != resizeMode) {
_resizeMode = resizeMode;

if (_resizeMode == RCTResizeModeRepeat) {
// Repeat resize mode is handled by the UIImage. Use scale to fill
// so the repeated image fills the UIImageView.
self.contentMode = UIViewContentModeScaleToFill;
} else {
self.contentMode = (UIViewContentMode)resizeMode;
}

if ([self sourceNeedsReload]) {
[self reloadImage];
}
Expand Down Expand Up @@ -230,7 +240,7 @@ - (void)reloadImage
size:imageSize
scale:imageScale
clipped:NO
resizeMode:(RCTResizeMode)self.contentMode
resizeMode:_resizeMode
progressBlock:progressHandler
completionBlock:^(NSError *error, UIImage *loadedImage) {
RCTImageView *strongSelf = weakSelf;
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Image/RCTImageViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, RCTResizeMode)
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
RCT_EXPORT_VIEW_PROPERTY(source, RCTImageSource)
RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
{
Expand Down
1 change: 1 addition & 0 deletions Libraries/Image/RCTResizeMode.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ typedef NS_ENUM(NSInteger, RCTResizeMode) {
RCTResizeModeCover = UIViewContentModeScaleAspectFill,
RCTResizeModeContain = UIViewContentModeScaleAspectFit,
RCTResizeModeStretch = UIViewContentModeScaleToFill,
RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values.
};

@interface RCTConvert(RCTResizeMode)
Expand Down
1 change: 1 addition & 0 deletions Libraries/Image/RCTResizeMode.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ @implementation RCTConvert(RCTResizeMode)
@"cover": @(RCTResizeModeCover),
@"contain": @(RCTResizeModeContain),
@"stretch": @(RCTResizeModeStretch),
@"repeat": @(RCTResizeModeRepeat),
}), RCTResizeModeStretch, integerValue)

@end

0 comments on commit 24879cd

Please sign in to comment.