Added `animationTransformer` on SDAnimatedImageView
This allows the animated image to apply post-transform Currently we don't change the old `SDWebImageTransformAnimatedImage` behavior. This feature is opt-in
This commit is contained in:
parent
0b10fcb544
commit
41dc9bef7b
|
@ -12,6 +12,7 @@
|
||||||
@interface DetailViewController ()
|
@interface DetailViewController ()
|
||||||
|
|
||||||
@property (strong, nonatomic) IBOutlet SDAnimatedImageView *imageView;
|
@property (strong, nonatomic) IBOutlet SDAnimatedImageView *imageView;
|
||||||
|
@property (assign) BOOL tintApplied;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -37,6 +38,39 @@
|
||||||
style:UIBarButtonItemStylePlain
|
style:UIBarButtonItemStylePlain
|
||||||
target:self
|
target:self
|
||||||
action:@selector(toggleAnimation:)];
|
action:@selector(toggleAnimation:)];
|
||||||
|
// Add a secret title click action to apply tint color
|
||||||
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||||
|
[button addTarget:self
|
||||||
|
action:@selector(toggleTint:)
|
||||||
|
forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[button setTitle:@"Tint" forState:UIControlStateNormal];
|
||||||
|
self.navigationItem.titleView = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)toggleTint:(UIResponder *)sender {
|
||||||
|
// tint for non-opaque animation
|
||||||
|
if (!self.imageView.isAnimating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDAnimatedImage *animatedImage = (SDAnimatedImage *)self.imageView.image;
|
||||||
|
if (animatedImage.sd_imageFormat == SDImageFormatGIF) {
|
||||||
|
// GIF is opaque
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BOOL containsAlpha = [SDImageCoderHelper CGImageContainsAlpha:animatedImage.CGImage];
|
||||||
|
if (!containsAlpha) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self.tintApplied) {
|
||||||
|
self.imageView.animationTransformer = nil;
|
||||||
|
} else {
|
||||||
|
self.imageView.animationTransformer = [SDImageTintTransformer transformerWithColor:UIColor.blackColor];
|
||||||
|
}
|
||||||
|
self.tintApplied = !self.tintApplied;
|
||||||
|
// refresh
|
||||||
|
UIImage *image = self.imageView.image;
|
||||||
|
self.imageView.image = nil;
|
||||||
|
self.imageView.image = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)toggleAnimation:(UIResponder *)sender {
|
- (void)toggleAnimation:(UIResponder *)sender {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#import "SDAnimatedImage.h"
|
#import "SDAnimatedImage.h"
|
||||||
#import "SDAnimatedImagePlayer.h"
|
#import "SDAnimatedImagePlayer.h"
|
||||||
|
#import "SDImageTransformer.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering.
|
A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering.
|
||||||
|
@ -28,6 +29,19 @@ NS_SWIFT_UI_ACTOR
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, strong, readonly, nullable) SDAnimatedImagePlayer *player;
|
@property (nonatomic, strong, readonly, nullable) SDAnimatedImagePlayer *player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The transformer for each decoded animated image frame.
|
||||||
|
We supports post-transform on animated image frame from version 5.20.
|
||||||
|
When you configure the transformer on `SDAnimatedImageView` and animation is playing, the `transformedImageWithImage:forKey:` will be called just after the frame is decoded. (The `key` arg is always empty for backward-compatible)
|
||||||
|
|
||||||
|
Example to tint the animated image with alpha channel into template:
|
||||||
|
* @code
|
||||||
|
imageView.animationTransformer = [SDImageTintTransformer transformerWithColor:UIColor.blackColor];
|
||||||
|
* @endcode
|
||||||
|
@note The `transformerKey` property is used to ensure the buffer cache available. So make sure it's correct value match the actual logic on transformer.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, strong, nullable) id<SDImageTransformer> animationTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Current display frame image. This value is KVO Compliance.
|
Current display frame image. This value is KVO Compliance.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,6 +15,70 @@
|
||||||
#import "SDInternalMacros.h"
|
#import "SDInternalMacros.h"
|
||||||
#import "objc/runtime.h"
|
#import "objc/runtime.h"
|
||||||
|
|
||||||
|
// A wrapper to implements the transformer on animated image, like tint color
|
||||||
|
@interface SDAnimatedImageFrameProvider : NSObject <SDAnimatedImageProvider>
|
||||||
|
@property (nonatomic, strong) id<SDAnimatedImageProvider> provider;
|
||||||
|
@property (nonatomic, strong) id<SDImageTransformer> transformer;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SDAnimatedImageFrameProvider
|
||||||
|
|
||||||
|
- (instancetype)initWithProvider:(id<SDAnimatedImageProvider>)provider transformer:(id<SDImageTransformer>)transformer {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_provider = provider;
|
||||||
|
_transformer = transformer;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
NSUInteger prime = 31;
|
||||||
|
NSUInteger result = 1;
|
||||||
|
NSUInteger providerHash = self.provider.hash;
|
||||||
|
NSUInteger transformerHash = self.transformer.transformerKey.hash;
|
||||||
|
result = prime * result + providerHash;
|
||||||
|
result = prime * result + transformerHash;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
if (nil == object) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (self == object) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
if (![object isKindOfClass:[self class]]) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return self.provider == [object provider]
|
||||||
|
&& [self.transformer.transformerKey isEqualToString:[object transformer].transformerKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)animatedImageData {
|
||||||
|
return self.provider.animatedImageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)animatedImageFrameCount {
|
||||||
|
return self.provider.animatedImageFrameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)animatedImageLoopCount {
|
||||||
|
return self.provider.animatedImageLoopCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index {
|
||||||
|
return [self.provider animatedImageDurationAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
|
||||||
|
UIImage *frame = [self.provider animatedImageFrameAtIndex:index];
|
||||||
|
return [self.transformer transformedImageWithImage:frame forKey:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface UIImageView () <CALayerDelegate>
|
@interface UIImageView () <CALayerDelegate>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -139,7 +203,14 @@
|
||||||
provider = (id<SDAnimatedImage>)image;
|
provider = (id<SDAnimatedImage>)image;
|
||||||
}
|
}
|
||||||
// Create animated player
|
// Create animated player
|
||||||
|
if (self.animationTransformer) {
|
||||||
|
// Check if post-transform animation available
|
||||||
|
provider = [[SDAnimatedImageFrameProvider alloc] initWithProvider:provider transformer:self.animationTransformer];
|
||||||
self.player = [SDAnimatedImagePlayer playerWithProvider:provider];
|
self.player = [SDAnimatedImagePlayer playerWithProvider:provider];
|
||||||
|
} else {
|
||||||
|
// Normal animation without post-transform
|
||||||
|
self.player = [SDAnimatedImagePlayer playerWithProvider:provider];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Update Frame Count
|
// Update Frame Count
|
||||||
self.player.totalFrameCount = [(id<SDAnimatedImage>)image animatedImageFrameCount];
|
self.player.totalFrameCount = [(id<SDAnimatedImage>)image animatedImageFrameCount];
|
||||||
|
|
|
@ -31,6 +31,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDThumbnailedKeyForKey(NSString * _Nullab
|
||||||
/**
|
/**
|
||||||
A transformer protocol to transform the image load from cache or from download.
|
A transformer protocol to transform the image load from cache or from download.
|
||||||
You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextImageTransformer`).
|
You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextImageTransformer`).
|
||||||
|
From v5.20, the transformer class also can be used on animated image frame post-transform logic, see `SDAnimatedImageView`.
|
||||||
|
|
||||||
@note The transform process is called from a global queue in order to not to block the main queue.
|
@note The transform process is called from a global queue in order to not to block the main queue.
|
||||||
*/
|
*/
|
||||||
|
@ -50,6 +51,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDThumbnailedKeyForKey(NSString * _Nullab
|
||||||
@required
|
@required
|
||||||
/**
|
/**
|
||||||
For each transformer, it must contains its cache key to used to store the image cache or query from the cache. This key will be appened after the original cache key generated by URL or from user.
|
For each transformer, it must contains its cache key to used to store the image cache or query from the cache. This key will be appened after the original cache key generated by URL or from user.
|
||||||
|
Which means, the cache should match what your transformer logic do. The same `input image` + `transformer key`, should always generate the same `output image`.
|
||||||
|
|
||||||
@return The cache key to appended after the original cache key. Should not be nil.
|
@return The cache key to appended after the original cache key. Should not be nil.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,7 +31,8 @@ SD_LOCK_DECLARE_STATIC(_providerFramePoolMapLock);
|
||||||
static NSMapTable *providerFramePoolMap;
|
static NSMapTable *providerFramePoolMap;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
providerFramePoolMap = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality valueOptions:NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality];
|
// Key use `hash` && `isEqual:`
|
||||||
|
providerFramePoolMap = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality valueOptions:NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality];
|
||||||
});
|
});
|
||||||
return providerFramePoolMap;
|
return providerFramePoolMap;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue