diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a81c8f7..9706de3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.2.7] - 2024-03-09 +- Fix AnimatedImage aspectRatio issue when ratio is nil #301 +- Upgrade to support visionOS on CocoaPods #298 + +## [2.2.6] - 2023-12-13 +- Try to workaround the #281 when imagePlayer stopPlaying trigger the Combine Publisher during deallocating #287 + +## [2.2.5] - 2023-11-29 +- Fix the AnimatedImgae rendering mode about compatible with SDWebImage 5.18+ + +## [2.2.4] - 2023-10-21 +- Allows to use UIImage/NSImage as defaults when init the AnimatedImage with JPEG data #277 + ## [2.2.3] - 2023-04-32 - Fix the issue that Static Library + Library Evolution cause the build issue on Swift 5.8 #263 diff --git a/Example/SDWebImageSwiftUI.xcodeproj/xcshareddata/xcschemes/SDWebImageSwiftUIDemo-watchOS WatchKit App.xcscheme b/Example/SDWebImageSwiftUI.xcodeproj/xcshareddata/xcschemes/SDWebImageSwiftUIDemo-watchOS WatchKit App.xcscheme index 3d1f081f..65df20bc 100644 --- a/Example/SDWebImageSwiftUI.xcodeproj/xcshareddata/xcschemes/SDWebImageSwiftUIDemo-watchOS WatchKit App.xcscheme +++ b/Example/SDWebImageSwiftUI.xcodeproj/xcshareddata/xcschemes/SDWebImageSwiftUIDemo-watchOS WatchKit App.xcscheme @@ -54,10 +54,8 @@ debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> - + - + - + - - - - - + diff --git a/README.md b/README.md index d64f3c3f..eb76b17e 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ All issue reports, feature requests, contributions, and GitHub stars are welcome + macOS 10.15+ (11+ Recommended) + tvOS 13+ (14+ Recommended) + watchOS 6+ (7+ Recommended) ++ visionOS 1+ ## SwiftUI 2.0 Compatibility @@ -229,7 +230,7 @@ Note: `AnimatedImage` supports both image url or image data for animated image f Note: `AnimatedImage` some methods like `.transition`, `.indicator` and `.aspectRatio` have the same naming as `SwiftUI.View` protocol methods. But the args receive the different type. This is because `AnimatedImage` supports to be used with UIKit/AppKit component and animation. If you find ambiguity, use full type declaration instead of the dot expression syntax. -Note: some of methods on `AnimatedImage` will return `some View`, a new Modified Content. You'll lose the type related modifier method. For this case, you can either reorder the method call, or use Native View in `.onViewUpdate` for rescue. +Note: some of methods on `AnimatedImage` will return `some View`, a new Modified Content. You'll lose the type related modifier method. For this case, you can either reorder the method call, or use native view (actually `SDAnimatedImageView`) in `.onViewUpdate`, use UIKIt/AppKit API for rescue. ```swift @@ -324,7 +325,7 @@ For more information, it's really recommended to check our demo, to learn detail ## Documentation -+ [SDWebImageSwiftUI API documentation](https://sdwebimage.github.io/SDWebImageSwiftUI/) ++ [SDWebImageSwiftUI API documentation](https://sdwebimage.github.io/documentation/sdwebimageswiftui/) + [SDWebImage API documentation](https://sdwebimage.github.io/) ## FAQ @@ -417,6 +418,42 @@ NavigationView { } ``` +#### Render vector image (SVG/PDF) with tint color + +Both `WebImage/AnimatedImage` supports to render the vector image, by using the `SVG/PDF` external coders. However they are different internally. + ++ `AnimatedImage`: use tech from Apple's symbol image and vector drawing, supports dynamic size changes without lossing details. And it use UIKit/AppKit based implementation and APIs. If you want, pass `.context(.imageThumbnailPixelSize: size)` to use bitmap rendering and get more pixels. ++ `WebImage`: draws vector image into a bitmap version. Which just like normal PNG. By default, we use vector image content size (SVG canvas size or PDF media box size). If you want, pass `.context(.imageThumbnailPixelSize: size)` to get more pixels. + +For bitmap rendering, you can also tint the SVG/PDF icons with custom colors (like symbol images), use the `.renderingMode(.template)` and `.tint(:)` or `.foregroundColor(:)` modifier, which matches `SwiftUI.Image` behavior. + ++ WebImage + +```swift +var body: some View { + WebImage(url: URL(string: "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/w3c.svg")) + .resizable() + .renderingMode(.template) + .foregroundColor(.red) // or `.tint(:)`, `.accentColor(:)` + .scaledToFit() +} +``` + ++ AnimatedImage + +```swift +var body: some View { + AnimatedImage(url: URL(string: "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/w3c.svg"), context: [.imageThumbnailPixelSize : CGSize(width: 100, height: 100)]) + .resizable() + .renderingMode(.template) + // seems `.foregroundColor(:)` does effect `UIView.tintColor`, use `tint(:)` or `.accentColor(:)` instead. + // Or you can use `onViewCreate(:)` to get native `SDAnimatedImageView` and set `tintColor` (AppKit use `contentTintColor`) + .tint(.red) + .scaledToFit() +} +``` + +See more: [Configuring and displaying symbol images in your UI](https://developer.apple.com/documentation/uikit/uiimage/configuring_and_displaying_symbol_images_in_your_ui?language=objc) #### Using with external loaders/caches/coders diff --git a/SDWebImageSwiftUI.podspec b/SDWebImageSwiftUI.podspec index 0c83570e..58ddaf2a 100644 --- a/SDWebImageSwiftUI.podspec +++ b/SDWebImageSwiftUI.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'SDWebImageSwiftUI' - s.version = '2.2.3' + s.version = '2.2.7' s.summary = 'SwiftUI Image loading and Animation framework powered by SDWebImage' s.description = <<-DESC @@ -25,6 +25,7 @@ It brings all your favorite features from SDWebImage, like async image loading, s.osx.deployment_target = '10.15' s.tvos.deployment_target = '13.0' s.watchos.deployment_target = '6.0' + s.visionos.deployment_target = '1.0' s.source_files = 'SDWebImageSwiftUI/Classes/**/*', 'SDWebImageSwiftUI/Module/*.h' s.pod_target_xcconfig = { diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index e454432f..49ce8f85 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -301,15 +301,29 @@ public struct AnimatedImage : PlatformViewRepresentable { // 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. if let name = imageModel.name, name != context.coordinator.imageLoading.imageName { + var image: PlatformImage? #if os(macOS) - let image = SDAnimatedImage(named: name, in: imageModel.bundle) + image = SDAnimatedImage(named: name, in: imageModel.bundle) + if image == nil { + // For static image, use NSImage as defaults + let bundle = imageModel.bundle ?? .main + image = bundle.image(forResource: name) + } #else - let image = SDAnimatedImage(named: name, in: imageModel.bundle, compatibleWith: nil) + image = SDAnimatedImage(named: name, in: imageModel.bundle, compatibleWith: nil) + if image == nil { + // For static image, use UIImage as defaults + image = PlatformImage(named: name, in: imageModel.bundle, compatibleWith: nil) + } #endif context.coordinator.imageLoading.imageName = name view.wrapped.image = image } else if let data = imageModel.data, data != context.coordinator.imageLoading.imageData { - let image = SDAnimatedImage(data: data, scale: imageModel.scale) + var image: PlatformImage? = SDAnimatedImage(data: data, scale: imageModel.scale) + if image == nil { + // For static image, use UIImage as defaults + image = PlatformImage.sd_image(with: data, scale: imageModel.scale) + } context.coordinator.imageLoading.imageData = data view.wrapped.image = image } else if let url = imageModel.url { @@ -422,7 +436,7 @@ public struct AnimatedImage : PlatformViewRepresentable { } // Animated Image does not support resizing mode and rendering mode - if let image = view.wrapped.image, !image.conforms(to: SDAnimatedImageProtocol.self) { + if let image = view.wrapped.image { var image = image // ResizingMode if let resizingMode = imageLayout.resizingMode, imageLayout.capInsets != EdgeInsets() { @@ -608,6 +622,11 @@ extension AnimatedImage { // Aspect Ratio @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension AnimatedImage { + func setImageLayoutAspectRatio(_ aspectRatio: CGFloat?, contentMode: ContentMode) { + self.imageLayout.aspectRatio = aspectRatio + self.imageLayout.contentMode = contentMode + } + /// Constrains this view's dimensions to the specified aspect ratio. /// - Parameters: /// - aspectRatio: The ratio of width to height to use for the resulting @@ -617,6 +636,7 @@ extension AnimatedImage { /// fill the parent context. /// - Returns: A view that constrains this view's dimensions to /// `aspectRatio`, using `contentMode` as its scaling algorithm. + @ViewBuilder public func aspectRatio(_ aspectRatio: CGFloat? = nil, contentMode: ContentMode) -> some View { // The `SwifUI.View.aspectRatio(_:contentMode:)` says: // If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio @@ -626,9 +646,12 @@ extension AnimatedImage { // But 2: there are no way to call a Protocol Extention default implementation in Swift 5.1 // So, we directly call the implementation detail modifier instead // Fired Radar: FB7413534 - self.imageLayout.aspectRatio = aspectRatio - self.imageLayout.contentMode = contentMode - return self.modifier(_AspectRatioLayout(aspectRatio: aspectRatio, contentMode: contentMode)) + let _ = self.setImageLayoutAspectRatio(aspectRatio, contentMode: contentMode) + if let aspectRatio { + self.modifier(_AspectRatioLayout(aspectRatio: aspectRatio, contentMode: contentMode)) + } else { + self + } } /// Constrains this view's dimensions to the aspect ratio of the given size. diff --git a/SDWebImageSwiftUI/Classes/ImageManager.swift b/SDWebImageSwiftUI/Classes/ImageManager.swift index d9bce8fa..668fb3b3 100644 --- a/SDWebImageSwiftUI/Classes/ImageManager.swift +++ b/SDWebImageSwiftUI/Classes/ImageManager.swift @@ -7,6 +7,7 @@ */ import SwiftUI +import Combine import SDWebImage /// A Image observable object for handle image load process. This drive the Source of Truth for image loading status. diff --git a/SDWebImageSwiftUI/Classes/ImagePlayer.swift b/SDWebImageSwiftUI/Classes/ImagePlayer.swift index 4e61e820..0ba09fc5 100644 --- a/SDWebImageSwiftUI/Classes/ImagePlayer.swift +++ b/SDWebImageSwiftUI/Classes/ImagePlayer.swift @@ -7,6 +7,7 @@ */ import SwiftUI +import Combine import SDWebImage /// A Image observable object for handle aniamted image playback. This is used to avoid `@State` update may capture the View struct type and cause memory leak. @@ -29,10 +30,6 @@ public final class ImagePlayer : ObservableObject { /// Animation playback mode public var playbackMode: SDAnimatedImagePlaybackMode = .normal - deinit { - player?.stopPlaying() - } - /// Current playing frame image @Published public var currentFrame: PlatformImage? diff --git a/SDWebImageSwiftUI/Classes/Indicator/Indicator.swift b/SDWebImageSwiftUI/Classes/Indicator/Indicator.swift index 37eb9030..3461b082 100644 --- a/SDWebImageSwiftUI/Classes/Indicator/Indicator.swift +++ b/SDWebImageSwiftUI/Classes/Indicator/Indicator.swift @@ -7,6 +7,7 @@ */ import Foundation +import Combine import SwiftUI /// A type to build the indicator diff --git a/SDWebImageSwiftUI/Module/Info.plist b/SDWebImageSwiftUI/Module/Info.plist index 49c664c0..24336cf6 100644 --- a/SDWebImageSwiftUI/Module/Info.plist +++ b/SDWebImageSwiftUI/Module/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 2.2.3 + 2.2.7 CFBundleVersion $(CURRENT_PROJECT_VERSION)