[Image] Add onLoadStart, onLoadProgress, onLoadError events to Image component
Summary: This PR adds 4 native events to NetworkImage. ![demo](http://zippy.gfycat.com/MelodicLawfulCaecilian.gif) Using these events I could wrap `Image` component into something like: ```javascript class NetworkImage extends React.Component { getInitialState() { return { downloading: false, progress: 0 } } render() { var loader = this.state.downloading ? <View style={this.props.loaderStyles}> <ActivityIndicatorIOS animating={true} size={'large'} /> <Text style={{color: '#bbb'}}>{this.state.progress}%</Text> </View> : null; return <Image source={this.props.source} onLoadStart={() => this.setState({downloading: true}) } onLoaded={() => this.setState({downloading: false}) } onLoadProgress={(e)=> this.setState({progress: Math.round(100 * e.nativeEvent.written / e.nativeEvent.total)}); onLoadError={(e)=> { alert('the image cannot be downloaded because: ', JSON.stringify(e)); this.setState({downloading: false}); }}> {loader} </Image> } } ``` Useful on slow connections and server errors. There are dozen lines of Objective C, which I don't have experience with. There are neither specific tests nor documentation yet. And I do realize that you're already working right now on better `<Image/>` (pipeline, new asset management, etc.). So this is basically a proof concept of events for images, and if this idea is not completely wrong I could improve it or help somehow. Closes https://github.com/facebook/react-native/pull/1318 Github Author: Dmitriy Loktev <unknownliveid@hotmail.com>
This commit is contained in:
parent
54c21ac651
commit
8e70c7f003
|
@ -105,6 +105,32 @@ var Image = React.createClass({
|
|||
* {nativeEvent: { layout: {x, y, width, height}}}.
|
||||
*/
|
||||
onLayout: PropTypes.func,
|
||||
/**
|
||||
* Invoked on load start
|
||||
*/
|
||||
onLoadStart: PropTypes.func,
|
||||
/**
|
||||
* Invoked on download progress with
|
||||
*
|
||||
* {nativeEvent: { written, total}}.
|
||||
*/
|
||||
onLoadProgress: PropTypes.func,
|
||||
/**
|
||||
* Invoked on load abort
|
||||
*/
|
||||
onLoadAbort: PropTypes.func,
|
||||
/**
|
||||
* Invoked on load error
|
||||
*
|
||||
* {nativeEvent: { error}}.
|
||||
*/
|
||||
onLoadError: PropTypes.func,
|
||||
/**
|
||||
* Invoked on load end
|
||||
*
|
||||
*/
|
||||
onLoaded: PropTypes.func
|
||||
|
||||
},
|
||||
|
||||
statics: {
|
||||
|
@ -161,6 +187,7 @@ var Image = React.createClass({
|
|||
if (this.props.defaultSource) {
|
||||
nativeProps.defaultImageSrc = this.props.defaultSource.uri;
|
||||
}
|
||||
nativeProps.progressHandlerRegistered = isNetwork && this.props.onLoadProgress;
|
||||
return <RawImage {...nativeProps} />;
|
||||
}
|
||||
});
|
||||
|
@ -178,6 +205,7 @@ var nativeOnlyProps = {
|
|||
src: true,
|
||||
defaultImageSrc: true,
|
||||
imageTag: true,
|
||||
progressHandlerRegistered: true
|
||||
};
|
||||
if (__DEV__) {
|
||||
verifyPropTypes(Image, RCTStaticImage.viewConfig, nativeOnlyProps);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (^RCTDataCompletionBlock)(NSURLResponse *response, NSData *data, NSError *error);
|
||||
typedef void (^RCTDataProgressBlock)(int64_t written, int64_t total);
|
||||
|
||||
@interface RCTDownloadTaskWrapper : NSObject <NSURLSessionDownloadDelegate>
|
||||
|
||||
@property (copy, nonatomic) RCTDataCompletionBlock completionBlock;
|
||||
@property (copy, nonatomic) RCTDataProgressBlock progressBlock;
|
||||
|
||||
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration delegateQueue:(NSOperationQueue *)delegateQueue;
|
||||
|
||||
- (NSURLSessionDownloadTask *)downloadData:(NSURL *)url progressBlock:(RCTDataProgressBlock)progressBlock completionBlock:(RCTDataCompletionBlock)completionBlock;
|
||||
|
||||
@property (nonatomic, assign) id<NSURLSessionDownloadDelegate> delegate;
|
||||
|
||||
@end
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
|
||||
#import "RCTDownloadTaskWrapper.h"
|
||||
|
||||
@implementation RCTDownloadTaskWrapper
|
||||
{
|
||||
NSURLSession *_URLSession;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration delegateQueue:(NSOperationQueue *)delegateQueue
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_URLSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSURLSessionDownloadTask *)downloadData:(NSURL *)url progressBlock:(RCTDataProgressBlock)progressBlock completionBlock:(RCTDataCompletionBlock)completionBlock
|
||||
{
|
||||
self.completionBlock = completionBlock;
|
||||
self.progressBlock = progressBlock;
|
||||
|
||||
NSURLSessionDownloadTask *task = [_URLSession downloadTaskWithURL:url completionHandler:nil];
|
||||
[task resume];
|
||||
return task;
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionTaskDelegate methods
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
|
||||
{
|
||||
if (self.completionBlock) {
|
||||
NSData *data = [NSData dataWithContentsOfURL:location];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.completionBlock(downloadTask.response, data, nil);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)didWriteData totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (self.progressBlock != nil) {
|
||||
self.progressBlock(totalBytesWritten, totalBytesExpectedToWrite);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didCompleteWithError:(NSError *)error
|
||||
{
|
||||
if (error && self.completionBlock) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.completionBlock(NULL, NULL, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
03559E7F1B064DAF00730281 /* RCTDownloadTaskWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 03559E7E1B064DAF00730281 /* RCTDownloadTaskWrapper.m */; };
|
||||
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */; };
|
||||
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */; };
|
||||
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */; };
|
||||
|
@ -32,6 +33,8 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
03559E7D1B064D3A00730281 /* RCTDownloadTaskWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTDownloadTaskWrapper.h; sourceTree = "<group>"; };
|
||||
03559E7E1B064DAF00730281 /* RCTDownloadTaskWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDownloadTaskWrapper.m; sourceTree = "<group>"; };
|
||||
1304D5A71AA8C4A30002E2BE /* RCTStaticImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStaticImage.h; sourceTree = "<group>"; };
|
||||
1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImage.m; sourceTree = "<group>"; };
|
||||
1304D5A91AA8C4A30002E2BE /* RCTStaticImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStaticImageManager.h; sourceTree = "<group>"; };
|
||||
|
@ -71,6 +74,8 @@
|
|||
children = (
|
||||
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */,
|
||||
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */,
|
||||
03559E7D1B064D3A00730281 /* RCTDownloadTaskWrapper.h */,
|
||||
03559E7E1B064DAF00730281 /* RCTDownloadTaskWrapper.m */,
|
||||
1304D5B01AA8C50D0002E2BE /* RCTGIFImage.h */,
|
||||
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */,
|
||||
58B511891A9E6BD600147676 /* RCTImageDownloader.h */,
|
||||
|
@ -168,6 +173,7 @@
|
|||
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */,
|
||||
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */,
|
||||
143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */,
|
||||
03559E7F1B064DAF00730281 /* RCTDownloadTaskWrapper.m in Sources */,
|
||||
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTDownloadTaskWrapper.h"
|
||||
|
||||
typedef void (^RCTDataDownloadBlock)(NSData *data, NSError *error);
|
||||
typedef void (^RCTImageDownloadBlock)(UIImage *image, NSError *error);
|
||||
|
||||
|
@ -22,6 +24,7 @@ typedef void (^RCTImageDownloadBlock)(UIImage *image, NSError *error);
|
|||
* the main thread. Returns a token that can be used to cancel the download.
|
||||
*/
|
||||
- (id)downloadDataForURL:(NSURL *)url
|
||||
progressBlock:(RCTDataProgressBlock)progressBlock
|
||||
block:(RCTDataDownloadBlock)block;
|
||||
|
||||
/**
|
||||
|
@ -35,6 +38,7 @@ typedef void (^RCTImageDownloadBlock)(UIImage *image, NSError *error);
|
|||
scale:(CGFloat)scale
|
||||
resizeMode:(UIViewContentMode)resizeMode
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
progressBlock:(RCTDataProgressBlock)progressBlock
|
||||
block:(RCTImageDownloadBlock)block;
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#import "RCTImageDownloader.h"
|
||||
|
||||
#import "RCTDownloadTaskWrapper.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
|
@ -45,12 +46,15 @@ CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
|||
return self;
|
||||
}
|
||||
|
||||
- (id)_downloadDataForURL:(NSURL *)url block:(RCTCachedDataDownloadBlock)block
|
||||
- (id)_downloadDataForURL:(NSURL *)url progressBlock:progressBlock block:(RCTCachedDataDownloadBlock)block
|
||||
{
|
||||
NSString *cacheKey = url.absoluteString;
|
||||
|
||||
__block BOOL cancelled = NO;
|
||||
__block NSURLSessionDataTask *task = nil;
|
||||
__block NSURLSessionDownloadTask *task = nil;
|
||||
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
RCTDownloadTaskWrapper *downloadTaskWrapper = [[RCTDownloadTaskWrapper alloc] initWithSessionConfiguration:config delegateQueue:nil];
|
||||
|
||||
dispatch_block_t cancel = ^{
|
||||
cancelled = YES;
|
||||
|
@ -85,7 +89,8 @@ CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
|||
});
|
||||
};
|
||||
|
||||
task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:url];
|
||||
task = [downloadTaskWrapper downloadData:url progressBlock:progressBlock completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||
if (!cancelled) {
|
||||
runBlocks(NO, data, error);
|
||||
}
|
||||
|
@ -93,12 +98,12 @@ CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
|||
if (response) {
|
||||
RCTImageDownloader *strongSelf = weakSelf;
|
||||
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data userInfo:nil storagePolicy:NSURLCacheStorageAllowed];
|
||||
[strongSelf->_cache storeCachedResponse:cachedResponse forDataTask:task];
|
||||
[strongSelf->_cache storeCachedResponse:cachedResponse forRequest:request];
|
||||
}
|
||||
task = nil;
|
||||
}];
|
||||
|
||||
[_cache getCachedResponseForDataTask:task completionHandler:^(NSCachedURLResponse *cachedResponse) {
|
||||
NSCachedURLResponse *cachedResponse = [_cache cachedResponseForRequest:request];
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
@ -108,16 +113,16 @@ CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
|||
} else {
|
||||
[task resume];
|
||||
}
|
||||
}];
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return [cancel copy];
|
||||
}
|
||||
|
||||
- (id)downloadDataForURL:(NSURL *)url block:(RCTDataDownloadBlock)block
|
||||
- (id)downloadDataForURL:(NSURL *)url progressBlock:(RCTDataProgressBlock)progressBlock block:(RCTDataDownloadBlock)block
|
||||
{
|
||||
return [self _downloadDataForURL:url block:^(BOOL cached, NSData *data, NSError *error) {
|
||||
return [self _downloadDataForURL:url progressBlock:progressBlock block:^(BOOL cached, NSData *data, NSError *error) {
|
||||
block(data, error);
|
||||
}];
|
||||
}
|
||||
|
@ -127,9 +132,10 @@ CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
|||
scale:(CGFloat)scale
|
||||
resizeMode:(UIViewContentMode)resizeMode
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
progressBlock:(RCTDataProgressBlock)progressBlock
|
||||
block:(RCTImageDownloadBlock)block
|
||||
{
|
||||
return [self downloadDataForURL:url block:^(NSData *data, NSError *error) {
|
||||
return [self downloadDataForURL:url progressBlock:progressBlock block:^(NSData *data, NSError *error) {
|
||||
if (!data || error) {
|
||||
block(nil, error);
|
||||
return;
|
||||
|
|
|
@ -121,7 +121,7 @@ static dispatch_queue_t RCTImageLoaderQueue(void)
|
|||
RCTDispatchCallbackOnMainQueue(callback, RCTErrorWithMessage(errorMessage), nil);
|
||||
return;
|
||||
}
|
||||
[[RCTImageDownloader sharedInstance] downloadDataForURL:url block:^(NSData *data, NSError *error) {
|
||||
[[RCTImageDownloader sharedInstance] downloadDataForURL:url progressBlock:nil block:^(NSData *data, NSError *error) {
|
||||
if (error) {
|
||||
RCTDispatchCallbackOnMainQueue(callback, error, nil);
|
||||
} else {
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTEventDispatcher;
|
||||
@class RCTImageDownloader;
|
||||
|
||||
@interface RCTNetworkImageView : UIView
|
||||
|
||||
- (instancetype)initWithImageDownloader:(RCTImageDownloader *)imageDownloader NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
imageDownloader:(RCTImageDownloader *)imageDownloader NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* An image that will appear while the view is loading the image from the network,
|
||||
|
|
|
@ -14,23 +14,27 @@
|
|||
#import "RCTGIFImage.h"
|
||||
#import "RCTImageDownloader.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@implementation RCTNetworkImageView
|
||||
{
|
||||
BOOL _deferred;
|
||||
BOOL _progressHandlerRegistered;
|
||||
NSURL *_imageURL;
|
||||
NSURL *_deferredImageURL;
|
||||
NSUInteger _deferSentinel;
|
||||
RCTImageDownloader *_imageDownloader;
|
||||
id _downloadToken;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
}
|
||||
|
||||
- (instancetype)initWithImageDownloader:(RCTImageDownloader *)imageDownloader
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher imageDownloader:(RCTImageDownloader *)imageDownloader
|
||||
{
|
||||
RCTAssertParam(imageDownloader);
|
||||
|
||||
if ((self = [super initWithFrame:CGRectZero])) {
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_progressHandlerRegistered = NO;
|
||||
_deferSentinel = 0;
|
||||
_imageDownloader = imageDownloader;
|
||||
self.userInteractionEnabled = NO;
|
||||
|
@ -56,6 +60,11 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
|
|||
[self _updateImage];
|
||||
}
|
||||
|
||||
- (void)setProgressHandlerRegistered:(BOOL)progressHandlerRegistered
|
||||
{
|
||||
_progressHandlerRegistered = progressHandlerRegistered;
|
||||
}
|
||||
|
||||
- (void)reactSetFrame:(CGRect)frame
|
||||
{
|
||||
[super reactSetFrame:frame];
|
||||
|
@ -89,8 +98,34 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
|
|||
self.layer.minificationFilter = kCAFilterTrilinear;
|
||||
self.layer.magnificationFilter = kCAFilterTrilinear;
|
||||
}
|
||||
[_eventDispatcher sendInputEventWithName:@"loadStart" body:@{ @"target": self.reactTag }];
|
||||
|
||||
RCTDataProgressBlock progressHandler = ^(int64_t written, int64_t total) {
|
||||
if (_progressHandlerRegistered) {
|
||||
NSDictionary *event = @{
|
||||
@"target": self.reactTag,
|
||||
@"written": @(written),
|
||||
@"total": @(total),
|
||||
};
|
||||
[_eventDispatcher sendInputEventWithName:@"loadProgress" body:event];
|
||||
}
|
||||
};
|
||||
|
||||
void (^errorHandler)(NSString *errorDescription) = ^(NSString *errorDescription) {
|
||||
NSDictionary *event = @{
|
||||
@"target": self.reactTag,
|
||||
@"error": errorDescription,
|
||||
};
|
||||
[_eventDispatcher sendInputEventWithName:@"loadError" body:event];
|
||||
};
|
||||
|
||||
void (^loadEndHandler)(void) = ^(void) {
|
||||
NSDictionary *event = @{ @"target": self.reactTag };
|
||||
[_eventDispatcher sendInputEventWithName:@"loaded" body:event];
|
||||
};
|
||||
|
||||
if ([imageURL.pathExtension caseInsensitiveCompare:@"gif"] == NSOrderedSame) {
|
||||
_downloadToken = [_imageDownloader downloadDataForURL:imageURL block:^(NSData *data, NSError *error) {
|
||||
_downloadToken = [_imageDownloader downloadDataForURL:imageURL progressBlock:progressHandler block:^(NSData *data, NSError *error) {
|
||||
if (data) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (imageURL != self.imageURL) {
|
||||
|
@ -102,13 +137,16 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
|
|||
self.layer.minificationFilter = kCAFilterLinear;
|
||||
self.layer.magnificationFilter = kCAFilterLinear;
|
||||
[self.layer addAnimation:animation forKey:@"contents"];
|
||||
loadEndHandler();
|
||||
});
|
||||
} else if (error) {
|
||||
RCTLogWarn(@"Unable to download image data. Error: %@", error);
|
||||
errorHandler([error description]);
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
_downloadToken = [_imageDownloader downloadImageForURL:imageURL size:self.bounds.size scale:RCTScreenScale() resizeMode:self.contentMode backgroundColor:self.backgroundColor block:^(UIImage *image, NSError *error) {
|
||||
_downloadToken = [_imageDownloader downloadImageForURL:imageURL size:self.bounds.size scale:RCTScreenScale()
|
||||
resizeMode:self.contentMode backgroundColor:self.backgroundColor
|
||||
progressBlock:progressHandler block:^(UIImage *image, NSError *error) {
|
||||
if (image) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (imageURL != self.imageURL) {
|
||||
|
@ -118,9 +156,10 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
|
|||
[self.layer removeAnimationForKey:@"contents"];
|
||||
self.layer.contentsScale = image.scale;
|
||||
self.layer.contents = (__bridge id)image.CGImage;
|
||||
loadEndHandler();
|
||||
});
|
||||
} else if (error) {
|
||||
RCTLogWarn(@"Unable to download image. Error: %@", error);
|
||||
errorHandler([error description]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -9,24 +9,37 @@
|
|||
|
||||
#import "RCTNetworkImageViewManager.h"
|
||||
|
||||
#import "RCTNetworkImageView.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#import "RCTImageDownloader.h"
|
||||
#import "RCTNetworkImageView.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@implementation RCTNetworkImageViewManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTNetworkImageView alloc] initWithImageDownloader:[RCTImageDownloader sharedInstance]];
|
||||
return [[RCTNetworkImageView alloc] initWithEventDispatcher:self.bridge.eventDispatcher imageDownloader:[RCTImageDownloader sharedInstance]];
|
||||
}
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
|
||||
RCT_REMAP_VIEW_PROPERTY(src, imageURL, NSURL)
|
||||
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
|
||||
RCT_EXPORT_VIEW_PROPERTY(progressHandlerRegistered, BOOL)
|
||||
|
||||
- (NSDictionary *)customDirectEventTypes
|
||||
{
|
||||
return @{
|
||||
@"loadStart": @{ @"registrationName": @"onLoadStart" },
|
||||
@"loadProgress": @{ @"registrationName": @"onLoadProgress" },
|
||||
@"loaded": @{ @"registrationName": @"onLoaded" },
|
||||
@"loadError": @{ @"registrationName": @"onLoadError" },
|
||||
@"loadAbort": @{ @"registrationName": @"onLoadAbort" },
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue