Permalink
Browse files

Add partial image loading to RCTImageView

Reviewed By: javache

Differential Revision: D3856918

fbshipit-source-id: ca98f8604213e7e583a188ccc4c25ea9d7aa9aa2
  • Loading branch information...
1 parent 048449b commit 820b1c0e46f781f6677caa3a62b59076bf2700e5 @mmmulani mmmulani committed with Facebook Github Bot 0 Sep 21, 2016
@@ -47,7 +47,7 @@ - (BOOL)canLoadImageURL:(NSURL *)requestURL
return _canLoadImageURLHandler(requestURL);
}
-- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode progressHandler:(RCTImageLoaderProgressBlock)progressHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
+- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode progressHandler:(RCTImageLoaderProgressBlock)progressHandler partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
return _loadImageURLHandler(imageURL, size, scale, resizeMode, progressHandler, completionHandler);
}
@@ -61,7 +61,7 @@ - (void)testImageLoading
[bridge.imageLoader loadImageWithURLRequest:urlRequest size:CGSizeMake(100, 100) scale:1.0 clipped:YES resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
XCTAssertEqual(progress, 1);
XCTAssertEqual(total, 1);
- } completionBlock:^(NSError *loadError, id loadedImage) {
+ } partialLoadBlock:nil completionBlock:^(NSError *loadError, id loadedImage) {
XCTAssertEqualObjects(loadedImage, image);
XCTAssertNil(loadError);
}];
@@ -92,7 +92,7 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority
[bridge.imageLoader loadImageWithURLRequest:urlRequest size:CGSizeMake(100, 100) scale:1.0 clipped:YES resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
XCTAssertEqual(progress, 1);
XCTAssertEqual(total, 1);
- } completionBlock:^(NSError *loadError, id loadedImage) {
+ } partialLoadBlock:nil completionBlock:^(NSError *loadError, id loadedImage) {
XCTAssertEqualObjects(loadedImage, image);
XCTAssertNil(loadError);
}];
@@ -36,6 +36,7 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
+ partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
// Using PhotoKit for iOS 8+
@@ -258,6 +258,13 @@ const Image = React.createClass({
*/
onError: PropTypes.func,
/**
+ * Invoked when a partial load of the image is complete. The definition of
+ * what constitutes a "partial load" is loader specific though this is meant
+ * for progressive JPEG loads.
+ * @platform ios
+ */
+ onPartialLoad: PropTypes.func,
+ /**
* Invoked when load completes successfully.
*/
onLoad: PropTypes.func,
@@ -14,6 +14,7 @@
#import "RCTResizeMode.h"
typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total);
+typedef void (^RCTImageLoaderPartialLoadBlock)(UIImage *image);
typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image);
typedef dispatch_block_t RCTImageLoaderCancellationBlock;
@@ -82,13 +83,17 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock;
* select the optimal dimensions for the loaded image. The `clipped` option
* controls whether the image will be clipped to fit the specified size exactly,
* or if the original aspect ratio should be retained.
+ * `partialLoadBlock` is meant for custom image loaders that do not ship with the core RN library.
+ * It is meant to be called repeatedly while loading the image as higher quality versions are decoded,
+ * for instance with progressive JPEGs.
*/
- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
size:(CGSize)size
scale:(CGFloat)scale
clipped:(BOOL)clipped
resizeMode:(RCTResizeMode)resizeMode
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
+ partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
/**
@@ -155,6 +160,7 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock;
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
+ partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
@optional
@@ -229,6 +229,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image
clipped:YES
resizeMode:RCTResizeModeStretch
progressBlock:nil
+ partialLoadBlock:nil
completionBlock:callback];
}
@@ -292,6 +293,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
+ partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate))completionBlock
{
{
@@ -343,6 +345,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
scale:scale
resizeMode:resizeMode
progressHandler:progressHandler
+ partialLoadHandler:partialLoadHandler
completionHandler:^(NSError *error, UIImage *image){
completionHandler(error, image, nil);
}];
@@ -366,6 +369,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
scale:scale
resizeMode:resizeMode
progressHandler:progressHandler
+ partialLoadHandler:partialLoadHandler
completionHandler:^(NSError *error, UIImage *image) {
completionHandler(error, image, nil);
}];
@@ -469,7 +473,11 @@ - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request
});
}];
- task.downloadProgressBlock = progressHandler;
+ task.downloadProgressBlock = ^(int64_t progress, int64_t total) {
+ if (progressHandler) {
+ progressHandler(progress, total);
+ }
+ };
if (task) {
if (!_pendingTasks) {
@@ -491,6 +499,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image
clipped:(BOOL)clipped
resizeMode:(RCTResizeMode)resizeMode
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
+ partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
{
__block volatile uint32_t cancelled = 0;
@@ -557,6 +566,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image
scale:scale
resizeMode:resizeMode
progressBlock:progressBlock
+ partialLoadBlock:partialLoadBlock
completionBlock:completionHandler];
return cancellationBlock;
}
@@ -693,6 +703,7 @@ - (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)ima
scale:1
resizeMode:RCTResizeModeStretch
progressBlock:NULL
+ partialLoadBlock:NULL
completionBlock:completion];
}
@@ -55,6 +55,7 @@ @interface RCTImageView ()
@property (nonatomic, copy) RCTDirectEventBlock onLoadStart;
@property (nonatomic, copy) RCTDirectEventBlock onProgress;
@property (nonatomic, copy) RCTDirectEventBlock onError;
+@property (nonatomic, copy) RCTDirectEventBlock onPartialLoad;
@property (nonatomic, copy) RCTDirectEventBlock onLoad;
@property (nonatomic, copy) RCTDirectEventBlock onLoadEnd;
@@ -296,6 +297,11 @@ - (void)reloadImage
};
}
+ __weak RCTImageView *weakSelf = self;
+ RCTImageLoaderPartialLoadBlock partialLoadHandler = ^(UIImage *image) {
+ [weakSelf imageLoaderLoadedImage:image error:nil forImageSource:source partial:YES];
+ };
+
CGSize imageSize = self.bounds.size;
CGFloat imageScale = RCTScreenScale();
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero)) {
@@ -304,9 +310,8 @@ - (void)reloadImage
imageScale = source.scale;
}
- __weak RCTImageView *weakSelf = self;
RCTImageLoaderCompletionBlock completionHandler = ^(NSError *error, UIImage *loadedImage) {
- [weakSelf imageLoaderLoadedImage:loadedImage error:error forImageSource:source];
+ [weakSelf imageLoaderLoadedImage:loadedImage error:error forImageSource:source partial:NO];
};
_reloadImageCancellationBlock =
@@ -316,13 +321,14 @@ - (void)reloadImage
clipped:NO
resizeMode:_resizeMode
progressBlock:progressHandler
+ partialLoadBlock:partialLoadHandler
completionBlock:completionHandler];
} else {
[self clearImage];
}
}
-- (void)imageLoaderLoadedImage:(UIImage *)loadedImage error:(NSError *)error forImageSource:(RCTImageSource *)source
+- (void)imageLoaderLoadedImage:(UIImage *)loadedImage error:(NSError *)error forImageSource:(RCTImageSource *)source partial:(BOOL)isPartialLoad
{
if (![source isEqual:_pendingImageSource]) {
// Bail out if source has changed since we started loading
@@ -340,8 +346,10 @@ - (void)imageLoaderLoadedImage:(UIImage *)loadedImage error:(NSError *)error for
}
void (^setImageBlock)(UIImage *) = ^(UIImage *image) {
- self->_imageSource = source;
- self->_pendingImageSource = nil;
+ if (!isPartialLoad) {
+ self->_imageSource = source;
+ self->_pendingImageSource = nil;
+ }
if (image.reactKeyframeAnimation) {
[self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"];
@@ -350,11 +358,17 @@ - (void)imageLoaderLoadedImage:(UIImage *)loadedImage error:(NSError *)error for
self.image = image;
}
- if (self->_onLoad) {
- self->_onLoad(onLoadParamsForSource(source));
- }
- if (self->_onLoadEnd) {
- self->_onLoadEnd(nil);
+ if (isPartialLoad) {
+ if (self->_onPartialLoad) {
+ self->_onPartialLoad(nil);
+ }
+ } else {
+ if (self->_onLoad) {
+ self->_onLoad(onLoadParamsForSource(source));
+ }
+ if (self->_onLoadEnd) {
+ self->_onLoadEnd(nil);
+ }
}
};
@@ -31,6 +31,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onLoadStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onPartialLoad, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
@@ -71,6 +71,7 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
+ partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
__block volatile uint32_t cancelled = 0;

0 comments on commit 820b1c0

Please sign in to comment.