Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ios/FastImage/FFFastImageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
@property (nonatomic, copy) RCTDirectEventBlock onFastImageLoadEnd;
@property (nonatomic, assign) RCTResizeMode resizeMode;
@property (nonatomic, strong) FFFastImageSource *source;
@property (nonatomic, strong) UIImage *defaultSource;
@property (nonatomic, strong) UIImage *placeholderImage;
@property (nonatomic, strong) NSString *defaultSource;
@property (nonatomic, strong) UIColor *imageColor;
#ifdef RCT_NEW_ARCH_ENABLED
@property(nonatomic) facebook::react::SharedViewEventEmitter eventEmitter;
Expand All @@ -29,4 +30,3 @@
- (void)didSetProps:(NSArray<NSString*>*)changedProps;

@end

113 changes: 101 additions & 12 deletions ios/FastImage/FFFastImageView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,48 @@ - (void) setImageColor: (UIColor*)imageColor {
}
}

- (UIImage*) makeImage: (UIImage*)image withTint: (UIColor*)color {
UIImage* newImage = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
UIGraphicsBeginImageContextWithOptions(image.size, NO, newImage.scale);
[color set];
[newImage drawInRect: CGRectMake(0, 0, image.size.width, newImage.size.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
- (UIImage *) makeImage:(UIImage *)image withTint:(UIColor *)color {
if (!image || !color || image.size.width <= 0 || image.size.height <= 0) {
return image;
}

// 使用 UIGraphicsImageRenderer (iOS 10+)
if (@available(iOS 10.0, *)) {
UIGraphicsImageRendererFormat *format =
[UIGraphicsImageRendererFormat defaultFormat];
format.scale = image.scale;
format.opaque = NO;

UIGraphicsImageRenderer *renderer =
[[UIGraphicsImageRenderer alloc] initWithSize:image.size format:format];
return [renderer imageWithActions:^(
UIGraphicsImageRendererContext *rendererContext) {
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
[color setFill];
UIRectFillUsingBlendMode(
CGRectMake(0, 0, image.size.width, image.size.height),
kCGBlendModeSourceAtop);
}];
}

UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
if (!context) {
UIGraphicsEndImageContext();
return newImage;
return image;
}

[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];

CGContextSetBlendMode(context, kCGBlendModeSourceAtop);
[color setFill];
CGContextFillRect(context,
CGRectMake(0, 0, image.size.width, image.size.height));

UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return tintedImage ?: image;
}

- (void) setImage: (UIImage*)image {
Expand Down Expand Up @@ -115,13 +149,68 @@ - (void) setSource: (FFFastImageSource*)source {
}
}

- (void) setDefaultSource: (UIImage*)defaultSource {
if (_defaultSource != defaultSource) {
_defaultSource = defaultSource;
- (void) setPlaceholderImage:(UIImage *)placeholderImage {
if (_placeholderImage != placeholderImage) {
_placeholderImage = placeholderImage;
_needsReload = YES;
}
}

- (void) setDefaultSource:(NSString *)defaultSource {
if (defaultSource.length == 0) {
return;
}

_defaultSource = [defaultSource copy];

UIImage *placeholder = nil;

NSURL *url = [NSURL URLWithString:defaultSource];
NSString *scheme = url.scheme.lowercaseString;

BOOL isHTTP = (scheme.length > 0 &&
([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]));

if (!isHTTP) {
NSURL *fileURL = nil;

if (url.isFileURL) {
fileURL = url;
} else {
fileURL = [NSURL fileURLWithPath:defaultSource];
}

placeholder = [UIImage imageWithContentsOfFile:fileURL.path];
self.placeholderImage = placeholder;
return;
}

#if DEBUG
__weak FFFastImageView *weakSelf = self;
NSURL *requestURL = url;

[[SDWebImageManager sharedManager] loadImageWithURL:requestURL
options:0
progress:nil
completed:^(UIImage * _Nullable image,
NSData * _Nullable data,
NSError * _Nullable error,
SDImageCacheType cacheType,
BOOL finished,
NSURL * _Nullable imageURL) {
__strong FFFastImageView *strongSelf = weakSelf;
if (!self) return;
if (!finished || error || !image) return;

if (![strongSelf.defaultSource isEqualToString:defaultSource]) return;

strongSelf.placeholderImage = image;
}];
#else
self.placeholderImage = nil;
#endif
}

- (void) didSetProps: (NSArray<NSString*>*)changedProps {
if (_needsReload) {
[self reloadImage];
Expand Down Expand Up @@ -235,14 +324,14 @@ - (void) reloadImage {

[self downloadImage: _source options: options context: context];
} else if (_defaultSource) {
[self setImage: _defaultSource];
[self setImage: _placeholderImage];
}
}

- (void) downloadImage: (FFFastImageSource*)source options: (SDWebImageOptions)options context: (SDWebImageContext*)context {
__weak FFFastImageView *weakSelf = self; // Always use a weak reference to self in blocks
[self sd_setImageWithURL: _source.url
placeholderImage: _defaultSource
placeholderImage: _placeholderImage
options: options
context: context
progress: ^(NSInteger receivedSize, NSInteger expectedSize, NSURL* _Nullable targetURL) {
Expand Down
5 changes: 4 additions & 1 deletion ios/FastImage/FFFastImageViewComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &

[fastImageView setSource: imageSource];

NSString *defaultSource = RCTNSStringFromStringNilIfEmpty(newViewProps.defaultSource);
[fastImageView setDefaultSource:defaultSource];


RCTResizeMode resizeMode;
switch (newViewProps.resizeMode) {
Expand All @@ -99,7 +102,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
break;
}
[fastImageView setResizeMode:resizeMode];

fastImageView.imageColor = RCTUIColorFromSharedColor(newViewProps.tintColor);

[super updateProps:props oldProps:oldProps];
Expand Down
3 changes: 2 additions & 1 deletion ios/FastImage/FFFastImageViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ - (FFFastImageView*)view {
}

RCT_EXPORT_VIEW_PROPERTY(source, FFFastImageSource)
RCT_EXPORT_VIEW_PROPERTY(defaultSource, UIImage)
RCT_EXPORT_VIEW_PROPERTY(defaultSource, NSString)
RCT_EXPORT_VIEW_PROPERTY(placeholderImage, UIImage)
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
RCT_EXPORT_VIEW_PROPERTY(onFastImageLoadStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onFastImageProgress, RCTDirectEventBlock)
Expand Down
66 changes: 33 additions & 33 deletions src/FastImageViewNativeComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import type {
ViewProps,
ColorValue,
} from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'
import type { ViewProps, ColorValue } from 'react-native'
import type {
Float,
WithDefault,
BubblingEventHandler,
Int32,
} from 'react-native/Libraries/Types/CodegenTypes';
Float,
WithDefault,
BubblingEventHandler,
Int32,
} from 'react-native/Libraries/Types/CodegenTypes'

type Headers = ReadonlyArray<Readonly<{name: string, value: string}>>;
type Priority = WithDefault< 'low' | 'normal' | 'high', 'normal'>
type CacheControl = WithDefault< 'immutable' | 'web' | 'cacheOnly', 'web'>
type Headers = ReadonlyArray<Readonly<{ name: string; value: string }>>
type Priority = WithDefault<'low' | 'normal' | 'high', 'normal'>
type CacheControl = WithDefault<'immutable' | 'web' | 'cacheOnly', 'web'>

type FastImageSource = Readonly<{
uri?: string,
headers?: Headers,
priority?: Priority,
cache?: CacheControl,
uri?: string
headers?: Headers
priority?: Priority
cache?: CacheControl
}>

type OnLoadEvent = Readonly<{
width: Float,
height: Float,
}>
width: Float
height: Float
}>

type OnProgressEvent = Readonly<{
loaded: Int32,
total: Int32,
}>
loaded: Int32
total: Int32
}>

interface NativeProps extends ViewProps {
onFastImageError?: BubblingEventHandler<Readonly<{}>>,
onFastImageLoad?: BubblingEventHandler<OnLoadEvent>,
onFastImageLoadEnd?: BubblingEventHandler<Readonly<{}>>,
onFastImageLoadStart?: BubblingEventHandler<Readonly<{}>>,
onFastImageProgress?: BubblingEventHandler<OnProgressEvent>,
source?: FastImageSource,
defaultSource?: string | null,
resizeMode?: WithDefault<'contain' | 'cover' | 'stretch' | 'center', 'cover'>,
tintColor?: ColorValue,
onFastImageError?: BubblingEventHandler<Readonly<{}>>
onFastImageLoad?: BubblingEventHandler<OnLoadEvent>
onFastImageLoadEnd?: BubblingEventHandler<Readonly<{}>>
onFastImageLoadStart?: BubblingEventHandler<Readonly<{}>>
onFastImageProgress?: BubblingEventHandler<OnProgressEvent>
source?: FastImageSource
defaultSource?: WithDefault<string, ''>
resizeMode?: WithDefault<
'contain' | 'cover' | 'stretch' | 'center',
'cover'
>
tintColor?: ColorValue
}

export default codegenNativeComponent<NativeProps>('FastImageView');
export default codegenNativeComponent<NativeProps>('FastImageView')
Loading