From 66a294032a41f489ef5407975b2a5276df825ceb Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Fri, 12 Apr 2019 02:43:05 -0700 Subject: [PATCH] Add border properties to RCTImageView Summary: `RCTImageView` is now a subclass of `RCTView` and includes `UIImageView` as it's subview. This enables the use of `borderRadius`, `borderWidth`, `borderColor` properties and all of their derivatives. Possible problem: Now `RCTImageView` is backed by two views (`RCTView` + `UIImageView`), not a single one. That's 4 `CALayers`. Possible workaround would be to insert the image directly into `self.layer.contents`. Reviewed By: RSNara Differential Revision: D14875673 fbshipit-source-id: 594b2cd1ddffc6627566e07983c6d8f0b37dc2bb --- Libraries/Image/RCTImageView.h | 4 +-- Libraries/Image/RCTImageView.m | 47 ++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Libraries/Image/RCTImageView.h b/Libraries/Image/RCTImageView.h index 38f82db455d..24c56d448ba 100644 --- a/Libraries/Image/RCTImageView.h +++ b/Libraries/Image/RCTImageView.h @@ -6,13 +6,13 @@ */ #import - +#import #import @class RCTBridge; @class RCTImageSource; -@interface RCTImageView : UIImageView +@interface RCTImageView : RCTView - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER; diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index 3b3d0ea709c..e407cb91dce 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -78,11 +78,13 @@ static NSDictionary *onLoadParamsForSource(RCTImageSource *source) // Whether the latest change of props requires the image to be reloaded BOOL _needsReload; + + UIImageView *_imageView; } - (instancetype)initWithBridge:(RCTBridge *)bridge { - if ((self = [super init])) { + if ((self = [super initWithFrame:CGRectZero])) { _bridge = bridge; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; @@ -94,6 +96,8 @@ static NSDictionary *onLoadParamsForSource(RCTImageSource *source) selector:@selector(clearImageIfDetached) name:UIApplicationDidEnterBackgroundNotification object:nil]; + _imageView = [[UIImageView alloc] init]; + [self addSubview:_imageView]; } return self; } @@ -105,10 +109,14 @@ static NSDictionary *onLoadParamsForSource(RCTImageSource *source) RCT_NOT_IMPLEMENTED(- (instancetype)init) +RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) + +RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) + - (void)updateWithImage:(UIImage *)image { if (!image) { - super.image = nil; + _imageView.image = nil; return; } @@ -125,16 +133,16 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } // Apply trilinear filtering to smooth out mis-sized images - self.layer.minificationFilter = kCAFilterTrilinear; - self.layer.magnificationFilter = kCAFilterTrilinear; + _imageView.layer.minificationFilter = kCAFilterTrilinear; + _imageView.layer.magnificationFilter = kCAFilterTrilinear; - super.image = image; + _imageView.image = image; } - (void)setImage:(UIImage *)image { image = image ?: _defaultImage; - if (image != self.image) { + if (image != _imageView.image) { [self updateWithImage:image]; } } @@ -157,7 +165,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) _needsReload = YES; } else { _capInsets = capInsets; - [self updateWithImage:self.image]; + [self updateWithImage:_imageView.image]; } } } @@ -166,7 +174,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) { if (_renderingMode != renderingMode) { _renderingMode = renderingMode; - [self updateWithImage:self.image]; + [self updateWithImage:_imageView.image]; } } @@ -186,9 +194,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) 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; + _imageView.contentMode = UIViewContentModeScaleToFill; } else { - self.contentMode = (UIViewContentMode)resizeMode; + _imageView.contentMode = (UIViewContentMode)resizeMode; } if ([self shouldReloadImageSourceAfterResize]) { @@ -211,8 +219,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) - (void)clearImage { [self cancelImageLoad]; - [self.layer removeAnimationForKey:@"contents"]; - self.image = nil; + [_imageView.layer removeAnimationForKey:@"contents"]; + _imageView.image = nil; _imageSource = nil; } @@ -351,10 +359,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } if (image.reactKeyframeAnimation) { - [self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"]; + [self->_imageView.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"]; } else { - [self.layer removeAnimationForKey:@"contents"]; - self.image = image; + [self->_imageView.layer removeAnimationForKey:@"contents"]; + self->_imageView.image = image; } if (isPartialLoad) { @@ -401,8 +409,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) _targetSize = frame.size; [self reloadImage]; } else if ([self shouldReloadImageSourceAfterResize]) { - CGSize imageSize = self.image.size; - CGFloat imageScale = self.image.scale; + CGSize imageSize = _imageView.image.size; + CGFloat imageScale = _imageView.image.scale; CGSize idealSize = RCTTargetSize(imageSize, imageScale, frame.size, RCTScreenScale(), (RCTResizeMode)self.contentMode, YES); @@ -450,4 +458,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } } +- (void)layoutSubviews { + [super layoutSubviews]; + _imageView.frame = self.bounds; +} + @end