diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h index 3e9d3e30f4cbaf..c9e4373314b443 100644 --- a/Libraries/Image/RCTImageLoader.h +++ b/Libraries/Image/RCTImageLoader.h @@ -52,6 +52,8 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock; @interface UIImage (React) +@property (nonatomic, copy) CAKeyframeAnimation *reactKeyframeAnimation; + /** * Memory bytes of the image with the default calculation of static image or GIF. Custom calculations of decoded bytes can be assigned manually. */ diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index dd5518fbb54773..06f89adbb35bcd 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -22,12 +22,27 @@ static NSInteger RCTImageBytesForImage(UIImage *image) { + CAKeyframeAnimation *keyFrameAnimation = [image reactKeyframeAnimation]; NSInteger singleImageBytes = image.size.width * image.size.height * image.scale * image.scale * 4; - return image.images ? image.images.count * singleImageBytes : singleImageBytes; + if (keyFrameAnimation) { + return keyFrameAnimation.values.count * singleImageBytes; + } else { + return image.images ? image.images.count * singleImageBytes : singleImageBytes; + } } @implementation UIImage (React) +- (CAKeyframeAnimation *)reactKeyframeAnimation +{ + return objc_getAssociatedObject(self, _cmd); +} + +- (void)setReactKeyframeAnimation:(CAKeyframeAnimation *)reactKeyframeAnimation +{ + objc_setAssociatedObject(self, @selector(reactKeyframeAnimation), reactKeyframeAnimation, OBJC_ASSOCIATION_COPY_NONATOMIC); +} + - (NSInteger)reactDecodedImageBytes { NSNumber *imageBytes = objc_getAssociatedObject(self, _cmd); @@ -265,9 +280,11 @@ - (void)setImageCache:(id)cache CGSizeEqualToSize(image.size, size)) { return image; } + CAKeyframeAnimation *animation = image.reactKeyframeAnimation; CGRect targetSize = RCTTargetRect(image.size, size, scale, resizeMode); CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetSize); image = RCTTransformImage(image, size, scale, transform); + image.reactKeyframeAnimation = animation; return image; } diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index ec4acf5e0b0b57..c193cbd3e51567 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -226,6 +226,7 @@ - (void)cancelImageLoad - (void)clearImage { [self cancelImageLoad]; + [_imageView.layer removeAnimationForKey:@"contents"]; self.image = nil; _imageSource = nil; } @@ -400,7 +401,18 @@ - (void)imageLoaderLoadedImage:(UIImage *)loadedImage error:(NSError *)error for self->_pendingImageSource = nil; } - self.image = image; + [self->_imageView.layer removeAnimationForKey:@"contents"]; + if (image.reactKeyframeAnimation) { + CGImageRef posterImageRef = (__bridge CGImageRef)[image.reactKeyframeAnimation.values firstObject]; + if (!posterImageRef) { + return; + } + // Apply renderingMode to animated image. + self->_imageView.image = [[UIImage imageWithCGImage:posterImageRef] imageWithRenderingMode:self->_renderingMode]; + [self->_imageView.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"]; + } else { + self.image = image; + } if (isPartialLoad) { if (self->_onPartialLoad) { diff --git a/Libraries/Image/RCTUIImageViewAnimated.m b/Libraries/Image/RCTUIImageViewAnimated.m index fb4a1d913e3709..f29999cbe7684b 100644 --- a/Libraries/Image/RCTUIImageViewAnimated.m +++ b/Libraries/Image/RCTUIImageViewAnimated.m @@ -85,11 +85,11 @@ - (void)setImage:(UIImage *)image if (self.image == image) { return; } - - [self stop]; - [self resetAnimatedImage]; if ([image respondsToSelector:@selector(animatedImageFrameAtIndex:)]) { + [self stop]; + [self resetAnimatedImage]; + NSUInteger animatedImageFrameCount = ((UIImage *)image).animatedImageFrameCount; // In case frame count is 0, there is no reason to continue.