Merge pull request #236 from SDWebImage/bugfix_webimage_no_stop_playing_quick_scroll
Fix the case which sometimes the player does not stop when WebImage it out of screen
This commit is contained in:
commit
c60b04b836
|
@ -33,7 +33,6 @@ public final class ImagePlayer : ObservableObject {
|
|||
|
||||
deinit {
|
||||
player?.stopPlaying()
|
||||
currentFrame = nil
|
||||
}
|
||||
|
||||
/// Current playing frame image
|
||||
|
@ -57,7 +56,7 @@ public final class ImagePlayer : ObservableObject {
|
|||
if let player = player {
|
||||
return player.isPlaying && waitingPlaying
|
||||
}
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
/// Current playing status
|
||||
|
@ -106,11 +105,21 @@ public final class ImagePlayer : ObservableObject {
|
|||
currentAnimatedImage = animatedImage
|
||||
if let imagePlayer = SDAnimatedImagePlayer(provider: animatedImage) {
|
||||
imagePlayer.animationFrameHandler = { [weak self] (index, frame) in
|
||||
self?.currentFrameIndex = index
|
||||
self?.currentFrame = frame
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
if (self.isPlaying) {
|
||||
self.currentFrameIndex = index
|
||||
self.currentFrame = frame
|
||||
}
|
||||
}
|
||||
imagePlayer.animationLoopHandler = { [weak self] (loopCount) in
|
||||
self?.currentLoopCount = loopCount
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
if (self.isPlaying) {
|
||||
self.currentLoopCount = loopCount
|
||||
}
|
||||
}
|
||||
// Setup configuration
|
||||
if let maxBufferSize = maxBufferSize {
|
||||
|
|
|
@ -102,8 +102,17 @@ public struct WebImage : View {
|
|||
}
|
||||
|
||||
public var body: some View {
|
||||
return Group {
|
||||
// Render Logic
|
||||
// Container
|
||||
return ZStack {
|
||||
// This empty Image is used to receive container's level appear/disappear to start/stop player, reduce CPU usage
|
||||
Image(platformImage: .empty)
|
||||
.onAppear {
|
||||
self.appearAction()
|
||||
}
|
||||
.onDisappear {
|
||||
self.disappearAction()
|
||||
}
|
||||
// Render Logic for actual animated image frame or static image
|
||||
if imageManager.image != nil && imageModel.url == imageManager.currentURL {
|
||||
if isAnimating && !imageManager.isIncremental {
|
||||
setupPlayer()
|
||||
|
@ -118,7 +127,7 @@ public struct WebImage : View {
|
|||
// Load Logic
|
||||
setupPlaceholder()
|
||||
.onPlatformAppear(appear: {
|
||||
setupManager()
|
||||
self.setupManager()
|
||||
if (self.imageManager.error == nil) {
|
||||
// Load remote image when first appear
|
||||
self.imageManager.load(url: imageModel.url, options: imageModel.options, context: imageModel.context)
|
||||
|
@ -205,36 +214,50 @@ public struct WebImage : View {
|
|||
}
|
||||
}
|
||||
|
||||
/// Container level to resume animation when appear
|
||||
func appearAction() {
|
||||
self.imagePlayer.startPlaying()
|
||||
}
|
||||
|
||||
/// Container level to stop animation when disappear
|
||||
func disappearAction() {
|
||||
if self.imageConfiguration.pausable {
|
||||
self.imagePlayer.pausePlaying()
|
||||
} else {
|
||||
self.imagePlayer.stopPlaying()
|
||||
}
|
||||
if self.imageConfiguration.purgeable {
|
||||
self.imagePlayer.clearFrameBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
/// Animated Image Support
|
||||
func setupPlayer() -> some View {
|
||||
let disappearAction = {
|
||||
// Only stop the player which is not intermediate status
|
||||
if !imagePlayer.isWaiting {
|
||||
if self.imageConfiguration.pausable {
|
||||
self.imagePlayer.pausePlaying()
|
||||
} else {
|
||||
self.imagePlayer.stopPlaying()
|
||||
}
|
||||
if self.imageConfiguration.purgeable {
|
||||
self.imagePlayer.clearFrameBuffer()
|
||||
}
|
||||
}
|
||||
}
|
||||
if let currentFrame = imagePlayer.currentFrame, imagePlayer.currentAnimatedImage == imageManager.image! {
|
||||
return configure(image: currentFrame).onPlatformAppear(appear: {
|
||||
self.imagePlayer.startPlaying()
|
||||
}, disappear: {
|
||||
disappearAction()
|
||||
})
|
||||
let shouldResetPlayer: Bool
|
||||
// Image compare should use ===/!==, which is faster than isEqual:
|
||||
if let animatedImage = imagePlayer.currentAnimatedImage, animatedImage !== imageManager.image! {
|
||||
shouldResetPlayer = true
|
||||
} else {
|
||||
return configure(image: imageManager.image!).onPlatformAppear(appear: {
|
||||
self.imagePlayer.stopPlaying()
|
||||
if let animatedImage = imageManager.image as? PlatformImage & SDAnimatedImageProvider {
|
||||
shouldResetPlayer = false
|
||||
}
|
||||
if let currentFrame = imagePlayer.currentFrame, !shouldResetPlayer {
|
||||
// Bind frame index to ID to ensure onDisappear called with sync
|
||||
return configure(image: currentFrame)
|
||||
.id("\(imageModel.url!):\(imagePlayer.currentFrameIndex)")
|
||||
.onAppear {}
|
||||
} else {
|
||||
return configure(image: imageManager.image!)
|
||||
.id("\(imageModel.url!):\(imagePlayer.currentFrameIndex)")
|
||||
.onAppear {
|
||||
if shouldResetPlayer {
|
||||
// Clear previous status
|
||||
self.imagePlayer.player = nil;
|
||||
self.imagePlayer.stopPlaying()
|
||||
self.imagePlayer.player = nil
|
||||
self.imagePlayer.currentFrame = nil;
|
||||
self.imagePlayer.currentFrameIndex = 0;
|
||||
self.imagePlayer.currentLoopCount = 0;
|
||||
}
|
||||
if let animatedImage = imageManager.image as? PlatformImage & SDAnimatedImageProvider {
|
||||
self.imagePlayer.customLoopCount = self.imageConfiguration.customLoopCount
|
||||
self.imagePlayer.maxBufferSize = self.imageConfiguration.maxBufferSize
|
||||
self.imagePlayer.runLoopMode = self.imageConfiguration.runLoopMode
|
||||
|
@ -244,9 +267,7 @@ public struct WebImage : View {
|
|||
self.imagePlayer.setupPlayer(animatedImage: animatedImage)
|
||||
self.imagePlayer.startPlaying()
|
||||
}
|
||||
}, disappear: {
|
||||
disappearAction()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@ class WebImageTests: XCTestCase {
|
|||
let imageView = WebImage(url: imageUrl)
|
||||
let introspectView = imageView.onSuccess { image, data, cacheType in
|
||||
#if os(macOS)
|
||||
let displayImage = try? imageView.inspect().group().image(0).actualImage().nsImage()
|
||||
let displayImage = try? imageView.inspect().zStack().image(1).actualImage().nsImage()
|
||||
#else
|
||||
let displayImage = try? imageView.inspect().group().image(0).actualImage().cgImage()
|
||||
let displayImage = try? imageView.inspect().zStack().image(1).actualImage().cgImage()
|
||||
#endif
|
||||
XCTAssertNotNil(displayImage)
|
||||
expectation.fulfill()
|
||||
|
@ -47,10 +47,10 @@ class WebImageTests: XCTestCase {
|
|||
if let animatedImage = image as? SDAnimatedImage {
|
||||
XCTAssertTrue(imageView.isAnimating)
|
||||
#if os(macOS)
|
||||
let displayImage = try? imageView.inspect().group().image(0).actualImage().nsImage()
|
||||
let displayImage = try? imageView.inspect().zStack().image(1).actualImage().nsImage()
|
||||
let size = displayImage?.size
|
||||
#else
|
||||
let displayImage = try? imageView.inspect().group().image(0).actualImage().cgImage()
|
||||
let displayImage = try? imageView.inspect().zStack().image(1).actualImage().cgImage()
|
||||
let size = CGSize(width: displayImage?.width ?? 0, height: displayImage?.height ?? 0)
|
||||
#endif
|
||||
XCTAssertNotNil(displayImage)
|
||||
|
@ -161,11 +161,11 @@ class WebImageTests: XCTestCase {
|
|||
let imageView = WebImage(url: imageUrl)
|
||||
let introspectView = imageView.onSuccess { image, data, cacheType in
|
||||
#if os(macOS)
|
||||
let displayImage = try? imageView.inspect().group().image(0).actualImage().nsImage()
|
||||
let displayImage = try? imageView.inspect().zStack().image(1).actualImage().nsImage()
|
||||
XCTAssertNotNil(displayImage)
|
||||
#else
|
||||
let displayImage = try? imageView.inspect().group().image(0).actualImage().cgImage()
|
||||
let orientation = try? imageView.inspect().group().image(0).actualImage().orientation()
|
||||
let displayImage = try? imageView.inspect().zStack().image(1).actualImage().cgImage()
|
||||
let orientation = try? imageView.inspect().zStack().image(1).actualImage().orientation()
|
||||
XCTAssertNotNil(displayImage)
|
||||
XCTAssertEqual(orientation, .leftMirrored)
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue