Add the advanced control on SDAnimatedImageView/Player

This commit is contained in:
DreamPiggy 2019-11-08 18:34:04 +08:00
parent 3c9c30c282
commit 09f2f74da8
3 changed files with 109 additions and 24 deletions

View File

@ -64,6 +64,10 @@ public struct AnimatedImage : PlatformViewRepresentable {
var incrementalLoad: Bool?
var maxBufferSize: UInt?
var customLoopCount: Int?
var runLoopMode: RunLoop.Mode?
var pausable: Bool?
var clearBufferWhenStopped: Bool?
var playBackRate: Double?
#if os(macOS) || os(iOS) || os(tvOS)
// These configurations only useful for web image loading
var indicator: SDWebImageIndicator?
@ -467,12 +471,40 @@ public struct AnimatedImage : PlatformViewRepresentable {
}
#elseif os(watchOS)
if let customLoopCount = self.customLoopCount {
view.wrapped.setAnimationRepeatCount(customLoopCount as NSNumber)
view.wrapped.animationRepeatCount = customLoopCount as NSNumber
} else {
// disable custom loop count
view.wrapped.setAnimationRepeatCount(nil)
view.wrapped.animationRepeatCount = nil
}
#endif
// RunLoop Mode
if let runLoopMode = self.runLoopMode {
view.wrapped.runLoopMode = runLoopMode
} else {
view.wrapped.runLoopMode = .common
}
// Pausable
if let pausable = self.pausable {
view.wrapped.resetFrameIndexWhenStopped = !pausable
} else {
view.wrapped.resetFrameIndexWhenStopped = false
}
// Clear Buffer
if let clearBufferWhenStopped = self.clearBufferWhenStopped {
view.wrapped.clearBufferWhenStopped = clearBufferWhenStopped
} else {
view.wrapped.clearBufferWhenStopped = false
}
// Playback Rate
if let playBackRate = self.playBackRate {
view.wrapped.playbackRate = playBackRate
} else {
view.wrapped.playbackRate = 1.0
}
}
}
@ -625,6 +657,48 @@ extension AnimatedImage {
result.incrementalLoad = incrementalLoad
return result
}
/// The runLoopMode when animation is playing on. Defaults is `.common`
/// You can specify a runloop mode to let it rendering.
/// - Note: This is useful for some cases, for example, always specify NSDefaultRunLoopMode, if you want to pause the animation when user scroll (for Mac user, drag the mouse or touchpad)
/// - Parameter runLoopMode: The runLoopMode for animation
public func runLoopMode(_ runLoopMode: RunLoop.Mode) -> AnimatedImage {
var result = self
result.runLoopMode = runLoopMode
return result
}
/// Whether or not to pause the animation (keep current frame), instead of stop the animation (frame index reset to 0). When the `isAnimating` binding value changed to false.
/// Defaults is true.
/// - Note: For some of use case, you may want to reset the frame index to 0 when stop, but some other want to keep the current frame index.
/// - Parameter pausable: Whether or not to pause the animation instead of stop the animation.
public func pausable(_ pausable: Bool) -> AnimatedImage {
var result = self
result.pausable = pausable
return result
}
/// Whether or not to clear frame buffer cache when stopped.
/// Note: This is useful when you want to limit the memory usage during frequently visibility changes (such as image view inside a list view, then push and pop)
/// - Parameter clearBufferWhenStopped: Whether or not to clear frame buffer cache when stopped.
public func clearBufferWhenStopped(_ clearBufferWhenStopped: Bool) -> AnimatedImage {
var result = self
result.clearBufferWhenStopped = clearBufferWhenStopped
return result
}
/// Control 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)
/// - Parameter playBackRate: The animation playback rate.
public func playBackRate(_ playBackRate: Double) -> AnimatedImage {
var result = self
result.playBackRate = playBackRate
return result
}
}
// Completion Handler

View File

@ -15,12 +15,17 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDAnimatedImageInterface : WKInterfaceImage
@property (nonatomic, assign, getter=isAnimating, readonly) BOOL animating;
@property (nonatomic, strong, nullable) NSNumber *animationRepeatCount;
@property (nonatomic, copy) NSRunLoopMode runLoopMode;
@property (nonatomic, assign) BOOL resetFrameIndexWhenStopped;
@property (nonatomic, assign) BOOL clearBufferWhenStopped;
@property (nonatomic, assign) double playbackRate;
- (instancetype)init WK_AVAILABLE_WATCHOS_ONLY(6.0);
/// Set the content mode for image
/// @param contentMode The contrent mode
- (void)setContentMode:(SDImageScaleMode)contentMode;
- (void)setAnimationRepeatCount:(nullable NSNumber *)repeatCount;
- (void)setRunLoopMode:(nonnull NSRunLoopMode)runLoopMode;
- (void)setPlaybackRate:(double)playbackRate;
/// Trigger the animation check when view appears/disappears
- (void)updateAnimation;

View File

@ -54,11 +54,9 @@
@property (nonatomic, strong, readwrite) UIImage *currentFrame;
@property (nonatomic, assign, readwrite) NSUInteger currentFrameIndex;
@property (nonatomic, assign, readwrite) NSUInteger currentLoopCount;
@property (nonatomic, strong) NSNumber *animationRepeatCount;
@property (nonatomic, assign, getter=isAnimating, readwrite) BOOL animating;
@property (nonatomic, assign) BOOL shouldAnimate;
@property (nonatomic, copy) NSRunLoopMode runLoopMode;
@property (nonatomic, assign) double playbackRate;
@property (nonatomic,strong) SDAnimatedImagePlayer *player; // The animation player.
@property (nonatomic, strong) SDAnimatedImagePlayer *player; // The animation player.
@property (nonatomic) id<CALayerProtocol> imageViewLayer; // The actual rendering layer.
@end
@ -162,10 +160,18 @@
- (void)updateAnimation {
[self updateShouldAnimate];
if (self.shouldAnimate) {
[self startAnimating];
} else {
[self stopAnimating];
if (!self.player) {
return;
}
// Filter automatically animating changes
if (self.shouldAnimate && self.isAnimating) {
[self.player startPlaying];
} else if (!self.shouldAnimate && !self.isAnimating) {
if (self.resetFrameIndexWhenStopped) {
[self.player stopPlaying];
} else {
[self.player pausePlaying];
}
}
}
@ -189,17 +195,8 @@
self.shouldAnimate = self.player && isVisible;
}
- (BOOL)isAnimating
{
if (self.player) {
return self.player.isPlaying;
} else {
id<UIImageViewProtocol> view = (id<UIImageViewProtocol>)[self _interfaceView];
return [view isAnimating];
}
}
- (void)startAnimating {
self.animating = YES;
if (self.player) {
[self.player startPlaying];
} else if (_image.images.count > 0) {
@ -208,6 +205,7 @@
}
- (void)startAnimatingWithImagesInRange:(NSRange)imageRange duration:(NSTimeInterval)duration repeatCount:(NSInteger)repeatCount {
self.animating = YES;
if (self.player) {
[self.player startPlaying];
} else if (_image.images.count > 0) {
@ -216,8 +214,16 @@
}
- (void)stopAnimating {
self.animating = NO;
if (self.player) {
[self.player stopPlaying];
if (self.resetFrameIndexWhenStopped) {
[self.player stopPlaying];
} else {
[self.player pausePlaying];
}
if (self.clearBufferWhenStopped) {
[self.player clearFrameBuffer];
}
} else if (_image.images.count > 0) {
[super stopAnimating];
}