Add shouldIncrementalLoad in SDAnimatedImageView to choose the animation behavior for progressive looading
This commit is contained in:
parent
00a0e01a32
commit
407b708b38
|
@ -28,7 +28,7 @@
|
|||
[super viewDidLoad];
|
||||
|
||||
// For animated GIF rendering, set `animates` to YES or will only show the first frame
|
||||
self.imageView2.animates = YES; // `SDAnimatedImageRep` be can used for built-in `NSImageView` to support better GIF & APNG rendering
|
||||
self.imageView2.animates = YES; // `SDAnimatedImageRep` can be used for built-in `NSImageView` to support better GIF & APNG rendering as well. No need `SDAnimatedImageView`
|
||||
self.imageView3.animates = YES;
|
||||
self.imageView4.animates = YES;
|
||||
self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
@required
|
||||
/**
|
||||
Initializes the image with an animated coder. You can use the coder to decode the image frame later.
|
||||
@note Normally we use `initWithData:scale:` to create custom animated image class. However, for progressive image decoding, we will use this instead.
|
||||
@note Normally we use `initWithData:scale:` to create custom animated image class. However, for progressive image decoding, we will use this with animated coder which conforms to `SDWebImageProgressiveCoder` as well instead.
|
||||
|
||||
@param animatedCoder An animated coder which conform `SDWebImageAnimatedCoder` protocol
|
||||
@param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property.
|
||||
|
|
|
@ -87,10 +87,11 @@
|
|||
}
|
||||
NSUInteger index = [value unsignedIntegerValue];
|
||||
float frameDuration = 0;
|
||||
// Through we currently process GIF only, in the 5.x we support APNG so we keep the extensibility
|
||||
if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) {
|
||||
// GIF
|
||||
frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource];
|
||||
} else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) {
|
||||
// APNG
|
||||
frameDuration = [[SDWebImageAPNGCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource];
|
||||
}
|
||||
if (!frameDuration) {
|
||||
|
|
|
@ -15,25 +15,26 @@
|
|||
/**
|
||||
A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering.
|
||||
Call `setImage:` with `UIImage(NSImage)` which conform to `SDAnimatedImage` protocol will start animated image rendering. Call with normal UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering
|
||||
For UIKit: use `-startAnimating`, `-stopAnimating` to control animating
|
||||
For AppKit: use `-setAnimates:` to control animating. This view is layer-backed.
|
||||
For UIKit: use `-startAnimating`, `-stopAnimating` to control animating. `isAnimating` to check animation state.
|
||||
For AppKit: use `-setAnimates:` to control animating, `animates` to check animation state. This view is layer-backed.
|
||||
*/
|
||||
@interface SDAnimatedImageView : UIImageView
|
||||
|
||||
/**
|
||||
Current display frame image
|
||||
Current display frame image.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly, nullable) UIImage *currentFrame;
|
||||
/**
|
||||
Current frame index, zero based
|
||||
Current frame index, zero based. This value is KVO Compliance.
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) NSUInteger currentFrameIndex;
|
||||
/**
|
||||
Current loop count since its latest animating
|
||||
Current loop count since its latest animating. This value is KVO Compliance.
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) NSUInteger currentLoopCount;
|
||||
/**
|
||||
YES to choose `animationRepeatCount` property instead of image's loop count for animation loop count. Default is NO.
|
||||
YES to choose `animationRepeatCount` property for animation loop count. No to use animated image's `animatedImageLoopCount` instead.
|
||||
Default is NO.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldCustomLoopCount;
|
||||
/**
|
||||
|
@ -42,11 +43,6 @@
|
|||
This class override UIImageView's `animationRepeatCount` property on iOS, use this property as well.
|
||||
*/
|
||||
@property (nonatomic, assign) NSInteger animationRepeatCount;
|
||||
/**
|
||||
Returns a Boolean value indicating whether the animation is running.
|
||||
This class override UIImageView's `animating` property on iOS, use this property as well.
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isAnimating) BOOL animating;
|
||||
/**
|
||||
Provide a max buffer size by bytes. This is used to adjust frame buffer count and can be useful when the decoding cost is expensive (such as Animated WebP software decoding). Default is 0.
|
||||
`0` means automatically adjust by calculating current memory usage.
|
||||
|
@ -54,12 +50,18 @@
|
|||
`NSUIntegerMax` means cache all the buffer. (Lowest CPU and Highest Memory)
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger maxBufferSize;
|
||||
/**
|
||||
Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+WebCache.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop.
|
||||
@note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior.
|
||||
@note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDWebImageProgressiveCoder` as well. Then call incremental update and incremental decode method to produce the image.
|
||||
Default is YES. Set to NO to only render the static poster for incremental animated image.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldIncrementalLoad;
|
||||
/**
|
||||
You can specify a runloop mode to let it rendering.
|
||||
Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device
|
||||
This value has no use on macOS
|
||||
*/
|
||||
@property (nonatomic, copy, nonnull) NSString *runLoopMode;
|
||||
@property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode NS_AVAILABLE_IOS(3_1);
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -210,6 +210,9 @@ dispatch_semaphore_signal(self->_lock);
|
|||
|
||||
- (void)commonInit
|
||||
{
|
||||
self.shouldCustomLoopCount = NO;
|
||||
self.shouldIncrementalLoad = YES;
|
||||
self.lock = dispatch_semaphore_create(1);
|
||||
#if SD_MAC
|
||||
self.wantsLayer = YES;
|
||||
// Default value from `NSImageView`
|
||||
|
@ -217,14 +220,12 @@ dispatch_semaphore_signal(self->_lock);
|
|||
self.imageScaling = NSImageScaleProportionallyDown;
|
||||
self.imageAlignment = NSImageAlignCenter;
|
||||
#endif
|
||||
self.runLoopMode = [[self class] defaultRunLoopMode];
|
||||
self.lock = dispatch_semaphore_create(1);
|
||||
#if SD_UIKIT
|
||||
self.runLoopMode = [[self class] defaultRunLoopMode];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)resetAnimatedImage
|
||||
{
|
||||
self.animatedImage = nil;
|
||||
|
@ -269,25 +270,8 @@ dispatch_semaphore_signal(self->_lock);
|
|||
return;
|
||||
}
|
||||
|
||||
// Check Progressive coding
|
||||
self.isProgressive = NO;
|
||||
if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) {
|
||||
NSData *currentData = [((UIImage<SDAnimatedImage> *)image) animatedImageData];
|
||||
if (currentData) {
|
||||
NSData *previousData;
|
||||
if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||
previousData = [((UIImage<SDAnimatedImage> *)self.image) animatedImageData];
|
||||
}
|
||||
// Check whether to use progressive coding
|
||||
if (!previousData) {
|
||||
// If previous data is nil
|
||||
self.isProgressive = YES;
|
||||
} else if ([currentData isEqualToData:previousData]) {
|
||||
// If current data is equal to previous data
|
||||
self.isProgressive = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check Progressive rendering
|
||||
[self updateIsProgressiveWithImage:image];
|
||||
|
||||
if (self.isProgressive) {
|
||||
// Reset all value, but keep current state
|
||||
|
@ -307,6 +291,10 @@ dispatch_semaphore_signal(self->_lock);
|
|||
if (animatedImageFrameCount <= 1) {
|
||||
return;
|
||||
}
|
||||
// If progressive rendering is disabled but animated image is incremental. Only show poster image
|
||||
if (!self.isProgressive && image.sd_isIncremental) {
|
||||
return;
|
||||
}
|
||||
self.animatedImage = (UIImage<SDAnimatedImage> *)image;
|
||||
self.totalFrameCount = animatedImageFrameCount;
|
||||
// Get the current frame and loop count.
|
||||
|
@ -346,6 +334,7 @@ dispatch_semaphore_signal(self->_lock);
|
|||
#endif
|
||||
}
|
||||
|
||||
#if SD_UIKIT
|
||||
- (void)setRunLoopMode:(NSString *)runLoopMode
|
||||
{
|
||||
if (![@[NSDefaultRunLoopMode, NSRunLoopCommonModes] containsObject:runLoopMode]) {
|
||||
|
@ -355,6 +344,7 @@ dispatch_semaphore_signal(self->_lock);
|
|||
_runLoopMode = runLoopMode;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark - Private
|
||||
- (NSOperationQueue *)fetchQueue
|
||||
|
@ -623,6 +613,33 @@ dispatch_semaphore_signal(self->_lock);
|
|||
self.shouldAnimate = self.animatedImage && self.totalFrameCount > 1 && isVisible;
|
||||
}
|
||||
|
||||
// Update progressive status only after `setImage:` call.
|
||||
- (void)updateIsProgressiveWithImage:(UIImage *)image
|
||||
{
|
||||
self.isProgressive = NO;
|
||||
if (!self.shouldIncrementalLoad) {
|
||||
// Early return
|
||||
return;
|
||||
}
|
||||
if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) {
|
||||
NSData *currentData = [((UIImage<SDAnimatedImage> *)image) animatedImageData];
|
||||
if (currentData) {
|
||||
NSData *previousData;
|
||||
if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||
previousData = [((UIImage<SDAnimatedImage> *)self.image) animatedImageData];
|
||||
}
|
||||
// Check whether to use progressive coding
|
||||
if (!previousData) {
|
||||
// If previous data is nil
|
||||
self.isProgressive = YES;
|
||||
} else if ([currentData isEqualToData:previousData]) {
|
||||
// If current data is equal to previous data
|
||||
self.isProgressive = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SD_MAC
|
||||
- (void)displayDidRefresh:(CVDisplayLinkRef)displayLink duration:(NSTimeInterval)duration
|
||||
#else
|
||||
|
@ -735,8 +752,8 @@ dispatch_semaphore_signal(self->_lock);
|
|||
}
|
||||
|
||||
|
||||
#pragma mark - CALayerDelegate (Informal)
|
||||
#pragma mark Providing the Layer's Content
|
||||
#pragma mark - CALayerDelegate
|
||||
|
||||
- (void)displayLayer:(CALayer *)layer
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue