Merge pull request #164 from SDWebImage/bugfix_appear_webimage
Fix the issue sometime the `WebImage` appear/disappear logic wrong. Using UIKit/AppKit to detect the visibility
This commit is contained in:
commit
74d142deca
|
@ -75,6 +75,14 @@
|
|||
32C43E3322FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */; };
|
||||
32C43E3422FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */; };
|
||||
32C43E3522FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */; };
|
||||
32CBA78025E4D7D800C6A8DC /* ImagePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */; };
|
||||
32CBA78125E4D7D800C6A8DC /* ImagePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */; };
|
||||
32CBA78225E4D7D800C6A8DC /* ImagePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */; };
|
||||
32CBA78325E4D7D800C6A8DC /* ImagePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */; };
|
||||
32CBA78425E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77F25E4D7D800C6A8DC /* SwiftUICompatibility.swift */; };
|
||||
32CBA78525E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77F25E4D7D800C6A8DC /* SwiftUICompatibility.swift */; };
|
||||
32CBA78625E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77F25E4D7D800C6A8DC /* SwiftUICompatibility.swift */; };
|
||||
32CBA78725E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77F25E4D7D800C6A8DC /* SwiftUICompatibility.swift */; };
|
||||
32D26A022446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
32D26A032446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
32D26A042446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
|
@ -137,6 +145,8 @@
|
|||
32C43E2922FD586200BE87F5 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/tvOS/SDWebImage.framework; sourceTree = "<group>"; };
|
||||
32C43E2D22FD586E00BE87F5 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/watchOS/SDWebImage.framework; sourceTree = "<group>"; };
|
||||
32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDWebImageSwiftUI.swift; sourceTree = "<group>"; };
|
||||
32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePlayer.swift; sourceTree = "<group>"; };
|
||||
32CBA77F25E4D7D800C6A8DC /* SwiftUICompatibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUICompatibility.swift; sourceTree = "<group>"; };
|
||||
32D26A012446B546005905DA /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
|
||||
32ED4825242A13030053338E /* ImageManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageManagerTests.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
@ -279,6 +289,8 @@
|
|||
32B933E323659A0700BB7CAD /* Transition */,
|
||||
326099472362E09E006EBB22 /* Indicator */,
|
||||
32C43DDC22FD54C600BE87F5 /* ImageManager.swift */,
|
||||
32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */,
|
||||
32CBA77F25E4D7D800C6A8DC /* SwiftUICompatibility.swift */,
|
||||
32C43DDE22FD54C600BE87F5 /* WebImage.swift */,
|
||||
32C43DDF22FD54C600BE87F5 /* AnimatedImage.swift */,
|
||||
32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */,
|
||||
|
@ -696,6 +708,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32B933E523659A1900BB7CAD /* Transition.swift in Sources */,
|
||||
32CBA78025E4D7D800C6A8DC /* ImagePlayer.swift in Sources */,
|
||||
32CBA78425E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1722FD583700BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848C236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84822363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
|
@ -713,6 +727,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32B933E623659A1900BB7CAD /* Transition.swift in Sources */,
|
||||
32CBA78125E4D7D800C6A8DC /* ImagePlayer.swift in Sources */,
|
||||
32CBA78525E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1A22FD583700BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848D236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84832363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
|
@ -730,6 +746,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32B933E723659A1900BB7CAD /* Transition.swift in Sources */,
|
||||
32CBA78225E4D7D800C6A8DC /* ImagePlayer.swift in Sources */,
|
||||
32CBA78625E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1D22FD583800BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848E236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84842363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
|
@ -747,6 +765,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32B933E823659A1900BB7CAD /* Transition.swift in Sources */,
|
||||
32CBA78325E4D7D800C6A8DC /* ImagePlayer.swift in Sources */,
|
||||
32CBA78725E4D7D800C6A8DC /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E2022FD583800BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848F236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84852363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) DreamPiggy <lizhuoli1126@126.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
#if os(iOS) || os(tvOS) || os(macOS)
|
||||
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
struct PlatformAppear: PlatformViewRepresentable {
|
||||
let appearAction: () -> Void
|
||||
let disappearAction: () -> Void
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
func makeUIView(context: Context) -> some UIView {
|
||||
let view = PlatformAppearView()
|
||||
view.appearAction = appearAction
|
||||
view.disappearAction = disappearAction
|
||||
return view
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIViewType, context: Context) {}
|
||||
#endif
|
||||
#if os(macOS)
|
||||
func makeNSView(context: Context) -> some NSView {
|
||||
let view = PlatformAppearView()
|
||||
view.appearAction = appearAction
|
||||
view.disappearAction = disappearAction
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: NSViewType, context: Context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
class PlatformAppearView: PlatformView {
|
||||
var appearAction: () -> Void = {}
|
||||
var disappearAction: () -> Void = {}
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
override func willMove(toWindow newWindow: UIWindow?) {
|
||||
if newWindow != nil {
|
||||
appearAction()
|
||||
} else {
|
||||
disappearAction()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
override func viewWillMove(toWindow newWindow: NSWindow?) {
|
||||
if newWindow != nil {
|
||||
appearAction()
|
||||
} else {
|
||||
disappearAction()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extension View {
|
||||
/// Used UIKit/AppKit behavior to detect the SwiftUI view's visibility.
|
||||
/// This hack is because of SwiftUI 1.0/2.0 buggy behavior. The built-in `onAppear` and `onDisappear` is so massive on some cases. Where UIKit/AppKit is solid.
|
||||
/// - Parameters:
|
||||
/// - appear: The action when view appears
|
||||
/// - disappear: The action when view disappears
|
||||
/// - Returns: Some view
|
||||
func onPlatformAppear(appear: @escaping () -> Void = {}, disappear: @escaping () -> Void = {}) -> some View {
|
||||
#if os(iOS) || os(tvOS) || os(macOS)
|
||||
return self.background(PlatformAppear(appearAction: appear, disappearAction: disappear))
|
||||
#else
|
||||
return self.onAppear(perform: appear).onDisappear(perform: disappear)
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -65,23 +65,22 @@ public struct WebImage : View {
|
|||
if isAnimating && !imageManager.isIncremental {
|
||||
if imagePlayer.currentFrame != nil {
|
||||
configure(image: imagePlayer.currentFrame!)
|
||||
.onAppear {
|
||||
imagePlayer.startPlaying()
|
||||
}
|
||||
.onDisappear {
|
||||
.onPlatformAppear(appear: {
|
||||
self.imagePlayer.startPlaying()
|
||||
}, disappear: {
|
||||
if self.pausable {
|
||||
imagePlayer.pausePlaying()
|
||||
self.imagePlayer.pausePlaying()
|
||||
} else {
|
||||
imagePlayer.stopPlaying()
|
||||
self.imagePlayer.stopPlaying()
|
||||
}
|
||||
if self.purgeable {
|
||||
imagePlayer.clearFrameBuffer()
|
||||
}
|
||||
self.imagePlayer.clearFrameBuffer()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
configure(image: imageManager.image!)
|
||||
.onReceive(imageManager.$image) { image in
|
||||
imagePlayer.setupPlayer(image: image)
|
||||
self.imagePlayer.setupPlayer(image: image)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -94,7 +93,7 @@ public struct WebImage : View {
|
|||
} else {
|
||||
setupPlaceholder()
|
||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||
.onAppear {
|
||||
.onPlatformAppear(appear: {
|
||||
// Load remote image when first appear
|
||||
if self.imageManager.isFirstLoad {
|
||||
self.imageManager.load()
|
||||
|
@ -105,14 +104,13 @@ public struct WebImage : View {
|
|||
if self.imageManager.image == nil && !self.imageManager.isIncremental {
|
||||
self.imageManager.load()
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
}, disappear: {
|
||||
guard self.cancelOnDisappear else { return }
|
||||
// When using prorgessive loading, the previous partial image will cause onDisappear. Filter this case
|
||||
if self.imageManager.image == nil && !self.imageManager.isIncremental {
|
||||
self.imageManager.cancel()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue