Merge pull request #2885 from dreampiggy/feature_animated_player_rate
Feature supports to control the AnimatedImage View/Player 's play rate
This commit is contained in:
commit
253a5eb7f2
2
Podfile
2
Podfile
|
@ -1,5 +1,3 @@
|
||||||
source 'https://github.com/CocoaPods/Specs.git'
|
|
||||||
|
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
def all_example_pods
|
def all_example_pods
|
||||||
|
|
|
@ -29,6 +29,14 @@
|
||||||
/// Total loop count for animated image rendering. Default is animated image's loop count.
|
/// Total loop count for animated image rendering. Default is animated image's loop count.
|
||||||
@property (nonatomic, assign) NSUInteger totalLoopCount;
|
@property (nonatomic, assign) NSUInteger totalLoopCount;
|
||||||
|
|
||||||
|
/// The animation playback rate. Default is 1.0
|
||||||
|
/// `1.0` means the normal speed.
|
||||||
|
/// `0.0` means stopping the animation.
|
||||||
|
/// `0.0-1.0` means the slow speed.
|
||||||
|
/// `> 1.0` means the fast speed.
|
||||||
|
/// `< 0.0` is not supported currently and stop animation. (may support reverse playback in the future)
|
||||||
|
@property (nonatomic, assign) double playbackRate;
|
||||||
|
|
||||||
/// 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.
|
/// 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.
|
/// `0` means automatically adjust by calculating current memory usage.
|
||||||
/// `1` means without any buffer cache, each of frames will be decoded and then be freed after rendering. (Lowest Memory and Highest CPU)
|
/// `1` means without any buffer cache, each of frames will be decoded and then be freed after rendering. (Lowest Memory and Highest CPU)
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
// Get the current frame and loop count.
|
// Get the current frame and loop count.
|
||||||
self.totalLoopCount = provider.animatedImageLoopCount;
|
self.totalLoopCount = provider.animatedImageLoopCount;
|
||||||
self.animatedProvider = provider;
|
self.animatedProvider = provider;
|
||||||
|
self.playbackRate = 1.0;
|
||||||
#if SD_UIKIT
|
#if SD_UIKIT
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||||
#endif
|
#endif
|
||||||
|
@ -227,17 +228,26 @@
|
||||||
NSUInteger currentFrameIndex = self.currentFrameIndex;
|
NSUInteger currentFrameIndex = self.currentFrameIndex;
|
||||||
NSUInteger nextFrameIndex = (currentFrameIndex + 1) % totalFrameCount;
|
NSUInteger nextFrameIndex = (currentFrameIndex + 1) % totalFrameCount;
|
||||||
|
|
||||||
|
NSTimeInterval playbackRate = self.playbackRate;
|
||||||
|
if (playbackRate <= 0) {
|
||||||
|
// Does not support <= 0 play rate
|
||||||
|
[self stopPlaying];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have the frame buffer firstly to improve performance
|
// Check if we have the frame buffer firstly to improve performance
|
||||||
if (!self.bufferMiss) {
|
if (!self.bufferMiss) {
|
||||||
// Then check if timestamp is reached
|
// Then check if timestamp is reached
|
||||||
self.currentTime += duration;
|
self.currentTime += duration;
|
||||||
NSTimeInterval currentDuration = [self.animatedProvider animatedImageDurationAtIndex:currentFrameIndex];
|
NSTimeInterval currentDuration = [self.animatedProvider animatedImageDurationAtIndex:currentFrameIndex];
|
||||||
|
currentDuration = currentDuration / playbackRate;
|
||||||
if (self.currentTime < currentDuration) {
|
if (self.currentTime < currentDuration) {
|
||||||
// Current frame timestamp not reached, return
|
// Current frame timestamp not reached, return
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.currentTime -= currentDuration;
|
self.currentTime -= currentDuration;
|
||||||
NSTimeInterval nextDuration = [self.animatedProvider animatedImageDurationAtIndex:nextFrameIndex];
|
NSTimeInterval nextDuration = [self.animatedProvider animatedImageDurationAtIndex:nextFrameIndex];
|
||||||
|
nextDuration = nextDuration / playbackRate;
|
||||||
if (self.currentTime > nextDuration) {
|
if (self.currentTime > nextDuration) {
|
||||||
// Do not skip frame
|
// Do not skip frame
|
||||||
self.currentTime = nextDuration;
|
self.currentTime = nextDuration;
|
||||||
|
|
|
@ -43,6 +43,15 @@
|
||||||
This class override UIImageView's `animationRepeatCount` property on iOS, use this property as well.
|
This class override UIImageView's `animationRepeatCount` property on iOS, use this property as well.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) NSInteger animationRepeatCount;
|
@property (nonatomic, assign) NSInteger animationRepeatCount;
|
||||||
|
/**
|
||||||
|
The animation playback rate. Default is 1.0.
|
||||||
|
`1.0` means the normal speed.
|
||||||
|
`0.0` means stopping the animation.
|
||||||
|
`0.0-1.0` means the slow speed.
|
||||||
|
`> 1.0` means the fast speed.
|
||||||
|
`< 0.0` is not supported currently and stop animation. (may support reverse playback in the future)
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) double playbackRate;
|
||||||
/**
|
/**
|
||||||
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.
|
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.
|
`0` means automatically adjust by calculating current memory usage.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
@interface SDAnimatedImageView () <CALayerDelegate> {
|
@interface SDAnimatedImageView () <CALayerDelegate> {
|
||||||
BOOL _initFinished; // Extra flag to mark the `commonInit` is called
|
BOOL _initFinished; // Extra flag to mark the `commonInit` is called
|
||||||
|
double _playbackRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, strong, readwrite) UIImage *currentFrame;
|
@property (nonatomic, strong, readwrite) UIImage *currentFrame;
|
||||||
|
@ -92,6 +93,7 @@
|
||||||
// So the properties which rely on this order, should using lazy-evaluation or do extra check in `setImage:`.
|
// So the properties which rely on this order, should using lazy-evaluation or do extra check in `setImage:`.
|
||||||
self.shouldCustomLoopCount = NO;
|
self.shouldCustomLoopCount = NO;
|
||||||
self.shouldIncrementalLoad = YES;
|
self.shouldIncrementalLoad = YES;
|
||||||
|
self.playbackRate = 1.0;
|
||||||
#if SD_MAC
|
#if SD_MAC
|
||||||
self.wantsLayer = YES;
|
self.wantsLayer = YES;
|
||||||
#endif
|
#endif
|
||||||
|
@ -147,6 +149,9 @@
|
||||||
self.player.totalLoopCount = self.animationRepeatCount;
|
self.player.totalLoopCount = self.animationRepeatCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Play Rate
|
||||||
|
self.player.playbackRate = self.playbackRate;
|
||||||
|
|
||||||
// Setup handler
|
// Setup handler
|
||||||
@weakify(self);
|
@weakify(self);
|
||||||
self.player.animationFrameHandler = ^(NSUInteger index, UIImage * frame) {
|
self.player.animationFrameHandler = ^(NSUInteger index, UIImage * frame) {
|
||||||
|
@ -191,6 +196,20 @@
|
||||||
return self.player.runLoopMode;
|
return self.player.runLoopMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setPlaybackRate:(double)playbackRate
|
||||||
|
{
|
||||||
|
_playbackRate = playbackRate;
|
||||||
|
self.player.playbackRate = playbackRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (double)playbackRate
|
||||||
|
{
|
||||||
|
if (!_initFinished) {
|
||||||
|
return 1.0; // Defaults to 1.0
|
||||||
|
}
|
||||||
|
return _playbackRate;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)shouldIncrementalLoad
|
- (BOOL)shouldIncrementalLoad
|
||||||
{
|
{
|
||||||
if (!_initFinished) {
|
if (!_initFinished) {
|
||||||
|
|
Loading…
Reference in New Issue