From bee118096b19e59f718c80cbd4ea2b681e972fce Mon Sep 17 00:00:00 2001 From: aleclarsoniv Date: Tue, 19 Jul 2016 03:33:37 -0700 Subject: [PATCH] Add Image resizeMode center to iOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Addresses this comment: https://github.com/facebook/react-native/issues/2296#issuecomment-232446493 This pull request adds the `center` value to `ImageResizeMode`. When set, it will center the image within its frame. If the image is larger than its frame, the image is downscaled while maintaining its aspect ratio. That is how the Android implementation works, too. Sorry, don't have time to write tests. 😢 Any reviewers should make sure `RCTTargetRect` returns the correct value when: - the image is smaller than its frame (ie: no downscaling needed) - the image is larger than its frame (should be downscaled to avoid clipping) Closes https://github.com/facebook/react-native/pull/8792 Differential Revision: D3586134 Pulled By: javache fbshipit-source-id: 78fb8e5928284003437dac2c9ad264fa584f73ec --- Libraries/Image/Image.ios.js | 2 +- Libraries/Image/RCTImageUtils.m | 38 +++++++++++++++++++++++++++------ Libraries/Image/RCTResizeMode.h | 1 + Libraries/Image/RCTResizeMode.m | 1 + 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 88b03b6ee1f..0fc1d20c5c3 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -173,7 +173,7 @@ const Image = React.createClass({ * - `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', 'repeat']), + resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center']), /** * A unique identifier for this element to be used in UI Automation * testing scripts. diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m index 515948a46e8..ce7a5530bba 100644 --- a/Libraries/Image/RCTImageUtils.m +++ b/Libraries/Image/RCTImageUtils.m @@ -53,9 +53,10 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, destSize.height = destSize.width / aspect; } - // Calculate target aspect ratio if needed (don't bother if resizeMode == stretch) + // Calculate target aspect ratio if needed CGFloat targetAspect = 0.0; - if (resizeMode != UIViewContentModeScaleToFill) { + if (resizeMode != RCTResizeModeCenter && + resizeMode != RCTResizeModeStretch) { targetAspect = destSize.width / destSize.height; if (aspect == targetAspect) { resizeMode = RCTResizeModeStretch; @@ -72,12 +73,12 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, if (targetAspect <= aspect) { // target is taller than content - sourceSize.width = destSize.width = destSize.width; + sourceSize.width = destSize.width; sourceSize.height = sourceSize.width / aspect; } else { // target is wider than content - sourceSize.height = destSize.height = destSize.height; + sourceSize.height = destSize.height; sourceSize.width = sourceSize.height * aspect; } return (CGRect){ @@ -92,7 +93,7 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, if (targetAspect <= aspect) { // target is taller than content - sourceSize.height = destSize.height = destSize.height; + sourceSize.height = destSize.height; sourceSize.width = sourceSize.height * aspect; destSize.width = destSize.height * targetAspect; return (CGRect){ @@ -102,7 +103,7 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, } else { // target is wider than content - sourceSize.width = destSize.width = destSize.width; + sourceSize.width = destSize.width; sourceSize.height = sourceSize.width / aspect; destSize.height = destSize.width / targetAspect; return (CGRect){ @@ -110,6 +111,26 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, RCTCeilSize(sourceSize, destScale) }; } + + case RCTResizeModeCenter: + + // Make sure the image is not clipped by the target. + if (sourceSize.height > destSize.height) { + sourceSize.width = destSize.width; + sourceSize.height = sourceSize.width / aspect; + } + if (sourceSize.width > destSize.width) { + sourceSize.height = destSize.height; + sourceSize.width = sourceSize.height * aspect; + } + + return (CGRect){ + { + RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale), + RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale), + }, + RCTCeilSize(sourceSize, destScale) + }; } } @@ -131,6 +152,10 @@ CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale, BOOL allowUpscaling) { switch (resizeMode) { + case RCTResizeModeCenter: + + return RCTTargetRect(sourceSize, destSize, destScale, resizeMode).size; + case RCTResizeModeStretch: if (!allowUpscaling) { @@ -207,6 +232,7 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale, } case RCTResizeModeRepeat: + case RCTResizeModeCenter: return NO; } diff --git a/Libraries/Image/RCTResizeMode.h b/Libraries/Image/RCTResizeMode.h index 4f623eac72f..2b791454243 100644 --- a/Libraries/Image/RCTResizeMode.h +++ b/Libraries/Image/RCTResizeMode.h @@ -13,6 +13,7 @@ typedef NS_ENUM(NSInteger, RCTResizeMode) { RCTResizeModeCover = UIViewContentModeScaleAspectFill, RCTResizeModeContain = UIViewContentModeScaleAspectFit, RCTResizeModeStretch = UIViewContentModeScaleToFill, + RCTResizeModeCenter = UIViewContentModeCenter, RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values. }; diff --git a/Libraries/Image/RCTResizeMode.m b/Libraries/Image/RCTResizeMode.m index 85f5766d631..6142fc6ab1f 100644 --- a/Libraries/Image/RCTResizeMode.m +++ b/Libraries/Image/RCTResizeMode.m @@ -15,6 +15,7 @@ RCT_ENUM_CONVERTER(RCTResizeMode, (@{ @"cover": @(RCTResizeModeCover), @"contain": @(RCTResizeModeContain), @"stretch": @(RCTResizeModeStretch), + @"center": @(RCTResizeModeCenter), @"repeat": @(RCTResizeModeRepeat), }), RCTResizeModeStretch, integerValue)