From 16211f68425453f3057bba64514abc57b279f594 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 17 May 2024 23:18:16 +0800 Subject: [PATCH] Supports to sync status for multiple SDAnimatedImageView who use the same image model --- .../project.pbxproj | 4 ++- .../SDWebImageSwiftUIDemo/ContentView.swift | 29 ++++++++++++++++++- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 11 +++---- SDWebImageSwiftUI/Classes/Environment.swift | 20 +++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 SDWebImageSwiftUI/Classes/Environment.swift diff --git a/Example/SDWebImageSwiftUI.xcodeproj/project.pbxproj b/Example/SDWebImageSwiftUI.xcodeproj/project.pbxproj index 2a26b45d..92845aca 100644 --- a/Example/SDWebImageSwiftUI.xcodeproj/project.pbxproj +++ b/Example/SDWebImageSwiftUI.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -194,6 +194,7 @@ 32E529512348A0DF00EA46FF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 32E529542348A0DF00EA46FF /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 32E529562348A0DF00EA46FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 32F4114B2BF72FE800B4ECB7 /* SDWebImage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SDWebImage; path = ../../SDWebImage; sourceTree = ""; }; 3E9F8B5F06960FFFBD1A5F99 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 54859B427E0A79E823713963 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; /* End PBXFileReference section */ @@ -432,6 +433,7 @@ 607FACC71AFB9204008FA782 = { isa = PBXGroup; children = ( + 32F4114B2BF72FE800B4ECB7 /* SDWebImage */, 3294617E2AA36761009E391B /* SDWebImageSwiftUI */, 607FACF51AFB993E008FA782 /* Podspec Metadata */, 320CDC2A22FADB44007CF858 /* SDWebImageSwiftUIDemo */, diff --git a/Example/SDWebImageSwiftUIDemo/ContentView.swift b/Example/SDWebImageSwiftUIDemo/ContentView.swift index 6e7e74cf..13a83b4a 100644 --- a/Example/SDWebImageSwiftUIDemo/ContentView.swift +++ b/Example/SDWebImageSwiftUIDemo/ContentView.swift @@ -17,6 +17,33 @@ class UserSettings: ObservableObject { #endif } +struct ContentView: View { + let imageURL = URL(string: "http://apng.onevcat.com/assets/elephant.png")! + + var body: some View { + ScrollView { + LazyVStack { + ForEach(1 ... 200, id: \.self) { index in + HStack { + AnimatedImage(url: imageURL) + .customLoopCount(0) + .playbackMode(.normal) + .resizable() + .frame(width: 100, height: 100) + .environment(\.animationGroup, "A") + AnimatedImage(url: imageURL) + .customLoopCount(0) + .playbackMode(.reverse) + .resizable() + .frame(width: 100, height: 100) + .environment(\.animationGroup, "B") + } + } + } + } + } +} + // Test Switching nil url struct ContentView3: View { @State var isOn = false @@ -107,7 +134,7 @@ struct ContentView2: View { } } -struct ContentView: View { +struct ContentView4: View { @State var imageURLs = [ "http://assets.sbnation.com/assets/2512203/dogflops.gif", "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif", diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 6c1b3ba4..c6bef37b 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -280,6 +280,9 @@ public struct AnimatedImage : PlatformViewRepresentable { func makeView(context: Context) -> AnimatedImageViewWrapper { let view = AnimatedImageViewWrapper() + if let group = context.environment.animationGroup { + view.wrapped.animationGroup = group + } if let viewCreateBlock = imageHandler.viewCreateBlock { viewCreateBlock(view.wrapped, context) } @@ -347,6 +350,9 @@ public struct AnimatedImage : PlatformViewRepresentable { } func updateView(_ view: AnimatedImageViewWrapper, context: Context) { + if let group = context.environment.animationGroup { + view.wrapped.animationGroup = group + } // Refresh image, imageModel is the Source of Truth, switch the type // Although we have Source of Truth, we can check the previous value, to avoid re-generate SDAnimatedImage, which is performance-cost. let kind = imageModel.kind @@ -384,11 +390,6 @@ public struct AnimatedImage : PlatformViewRepresentable { static func dismantleView(_ view: AnimatedImageViewWrapper, coordinator: Coordinator) { view.wrapped.sd_cancelCurrentImageLoad() - #if os(macOS) - view.wrapped.animates = false - #else - view.wrapped.stopAnimating() - #endif if let viewDestroyBlock = viewDestroyBlock { viewDestroyBlock(view.wrapped, coordinator) } diff --git a/SDWebImageSwiftUI/Classes/Environment.swift b/SDWebImageSwiftUI/Classes/Environment.swift new file mode 100644 index 00000000..b3eefb8b --- /dev/null +++ b/SDWebImageSwiftUI/Classes/Environment.swift @@ -0,0 +1,20 @@ +/* + * This file is part of the SDWebImage package. + * (c) DreamPiggy + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import SwiftUI + +public struct AnimationGroup: EnvironmentKey { + public static var defaultValue: String? { nil } +} + +extension EnvironmentValues { + public var animationGroup: String? { + get { self[AnimationGroup.self] } + set { self[AnimationGroup.self] = newValue } + } +}