[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7121":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":17,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":37,"readmeContent":38,"aiSummary":39,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":40,"discoverSource":41},7121,"SDWebImageSwiftUI","SDWebImage\u002FSDWebImageSwiftUI","SDWebImage","SwiftUI Image loading and Animation framework powered by SDWebImage","https:\u002F\u002Fsdwebimage.github.io\u002FSDWebImageSwiftUI",null,"Swift",2546,256,22,81,0,2,29.23,"MIT License",false,"master",true,[24,25,26,27,28,29,30,31,32,33,34,35,36],"animated-webp","apng","gif","ios","macos","sdwebimage","swift","swift-ui","swiftpm","swiftui","tvos","watchos","webp","2026-06-12 02:01:34","# SDWebImageSwiftUI\n\n[![CI Status](https:\u002F\u002Ftravis-ci.org\u002FSDWebImage\u002FSDWebImageSwiftUI.svg?branch=master)](https:\u002F\u002Ftravis-ci.org\u002FSDWebImage\u002FSDWebImageSwiftUI)\n[![Version](https:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fv\u002FSDWebImageSwiftUI.svg)](https:\u002F\u002Fcocoapods.org\u002Fpods\u002FSDWebImageSwiftUI)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fl\u002FSDWebImageSwiftUI.svg)](https:\u002F\u002Fcocoapods.org\u002Fpods\u002FSDWebImageSwiftUI)\n[![Platform](https:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fp\u002FSDWebImageSwiftUI.svg)](https:\u002F\u002Fcocoapods.org\u002Fpods\u002FSDWebImageSwiftUI)\n[![Carthage compatible](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FCarthage-compatible-brightgreen.svg)](https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage)\n[![SwiftPM compatible](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwiftPM-compatible-brightgreen.svg)](https:\u002F\u002Fswift.org\u002Fpackage-manager\u002F)\n[![codecov](https:\u002F\u002Fcodecov.io\u002Fgh\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Fbranch\u002Fmaster\u002Fgraph\u002Fbadge.svg)](https:\u002F\u002Fcodecov.io\u002Fgh\u002FSDWebImage\u002FSDWebImageSwiftUI)\n\n> If you support iOS 15+\u002FmacOS 12+ only and don't care about animated image format, try SwiftUI's [AsyncImage](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fswiftui\u002Fasyncimage)\n\n## What's for\n\nSDWebImageSwiftUI is a SwiftUI image loading framework, which based on [SDWebImage](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage).\n\nIt brings all your favorite features from SDWebImage, like async image loading, memory\u002Fdisk caching, animated image playback and performances.\n\nThe framework provide the different View structs, which API match the SwiftUI framework guideline. If you're familiar with `Image`, you'll find it easy to use `WebImage` and `AnimatedImage`.\n\n## Apple VisionOS\n\nFrom v3.0.0, SDWebImageSwiftUI can be compiled for visionOS platform. However, due to the lacking package manager support (need tools update), we don't support CocoaPods\u002FSPM yet.\n\nYou can only use the Xcode's built-in package manager dependency to build on visionOS.\n\nTo run the visionOS example, you need to clone and add both `SDWebImage` and `SDWebImageSwiftUI`, open the `SDWebImageSwiftUI.xcworkspace` and drag those folders to become local package dependency, see: [Editing a package dependency as a local package](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fxcode\u002Fediting-a-package-dependency-as-a-local-package)\n\nIf you really want to build framework instead of using Xcode's package dependency, following the manual steps below:\n\n1. Clone SDWebImage, open `SDWebImage.xcodeproj` and build `SDWebImage` target for visionOS platform (Change `MACH_O_TYPE` to static library if you need)\n2. Clone SDWebImageSwiftUI, create directory at `Carthage\u002FBuild\u002FvisionOS` and copy `SDWebImage.framework` into it\n3. Open `SDWebImageSwiftUI.xcodeproj` and build `SDWebImageSwiftUI visionOS` target\n\n## Features\n\nSince SDWebImageSwiftUI is built on top of SDWebImage, it provide both the out-of-box features as well as advanced powerful features you may want in real world Apps. Check our [Wiki](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage\u002Fwiki\u002FAdvanced-Usage) when you need:\n\n- [x] Animated Image full-stack solution, with balance of CPU && RAM\n- [x] Progressive image loading, with animation support\n- [x] Reusable download, never request single URL twice\n- [x] URL Request \u002F Response Modifier, provide custom HTTP Header\n- [x] Image Transformer, apply corner radius or CIFilter\n- [x] Multiple caches system, query from different source\n- [x] Multiple loaders system, load from different resource\n\nYou can also get all benefits from the existing community around with SDWebImage. You can have massive image format support (GIF\u002FAPNG\u002FWebP\u002FHEIF\u002FAVIF\u002FSVG\u002FPDF) via [Coder Plugins](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage\u002Fwiki\u002FCoder-Plugin-List), PhotoKit support via [SDWebImagePhotosPlugin](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImagePhotosPlugin), Firebase integration via [FirebaseUI](https:\u002F\u002Fgithub.com\u002Ffirebase\u002FFirebaseUI-iOS), etc.\n\nBesides all these features, we do optimization for SwiftUI, like Binding, View Modifier, using the same design pattern to become a good SwiftUI citizen.\n\n## Version\n\nThis framework is under heavily development, it's recommended to use [the latest release](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Freleases) as much as possible (including SDWebImage dependency).\n\nThis framework follows [Semantic Versioning](https:\u002F\u002Fsemver.org\u002F). Each source-break API changes will bump to a major version.\n\n## Changelog\n\nThis project use [keep a changelog](https:\u002F\u002Fkeepachangelog.com\u002Fen\u002F1.0.0\u002F) format to record the changes. Check the [CHANGELOG.md](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Fblob\u002Fmaster\u002FCHANGELOG.md) about the changes between versions. The changes will also be updated in Release page.\n\n## Contribution\n\nAll issue reports, feature requests, contributions, and GitHub stars are welcomed. Hope for active feedback and promotion if you find this framework useful.\n\n## Requirements\n\n+ Xcode 14+\n+ iOS 14+\n+ macOS 11+\n+ tvOS 14+\n+ watchOS 7+\n+ visionOS 1+\n\n## for SwiftUI 1.0 (iOS 13)\n\niOS 14(macOS 11) introduce the SwiftUI 2.0, which keep the most API compatible, but changes many internal behaviors, which breaks the SDWebImageSwiftUI's function.\n\nFrom v3.0.0, SDWebImageSwiftUI drop iOS 13 support. To use on iOS 13, checkout the latest v2.x version (or using [2.x](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Ftree\u002F2.x) branch) instead.\n\n## for future transition\n\nSince SDWebImage 6.0 will introduce mixed Swift\u002FObjc codebase, this repo will migrate into [SDWebImage Core Repo](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage).\n\nBut don't worry, we will use the automatic cross module overlay, whic means, you can use:\n\n```swift\nimport SwiftUI\nimport SDWebImage\n```\n\nto works like:\n\n```\nimport SwiftUI\nimport SDWebImage\nimport SDWebImageSwiftUI \u002F\u002F \u003C-- Automatic infer this\n```\n\nYou will automatically link the `SDWebImageSwiftUI`, and this library's naming will still be preserved in SPM target. So the transition is smooth for most of you, I don't want to bump another major version. **The 3.x is the final version for SDWebImageSwiftUI dedicated repo**\n\nNote: For super advanced user, if you using some custom Swift toolchain, be sure to pass `-Xfrontend -enable-cross-import-overlays`\n\n## Installation\n\n#### Swift Package Manager\n\nSDWebImageSwiftUI is available through [Swift Package Manager](https:\u002F\u002Fswift.org\u002Fpackage-manager\u002F).\n\n+ For App integration\n\nFor App integration, you should using Xcode 12 or higher, to add this package to your App target. To do this, check [Adding Package Dependencies to Your App](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fxcode\u002Fadding_package_dependencies_to_your_app?language=objc) about the step by step tutorial using Xcode.\n\n+ For downstream framework\n\nFor downstream framework author, you should create a `Package.swift` file into your git repo, then add the following line to mark your framework dependent our SDWebImageSwiftUI.\n\n```swift\nlet package = Package(\n    dependencies: [\n        .package(url: \"https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageSwiftUI.git\", from: \"3.0.0\")\n    ],\n)\n```\n\n#### CocoaPods\n\nSDWebImageSwiftUI is available through [CocoaPods](https:\u002F\u002Fcocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'SDWebImageSwiftUI'\n```\n\n#### Carthage\n\nSDWebImageSwiftUI is available through [Carthage](https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage).\n\n```\ngithub \"SDWebImage\u002FSDWebImageSwiftUI\"\n```\n\n## Usage\n\n### Using `WebImage` to load network image\n\n- [x] Supports placeholder and detail options control for image loading as SDWebImage\n- [x] Supports progressive image loading (like baseline)\n- [x] Supports success\u002Ffailure\u002Fprogress changes event for custom handling\n- [x] Supports indicator with activity\u002Fprogress indicator and customization\n- [x] Supports built-in animation and transition, powered by SwiftUI\n- [x] Supports animated image as well!\n\n```swift\nvar body: some View {\n    WebImage(url: URL(string: \"https:\u002F\u002Fnokiatech.github.io\u002Fheif\u002Fcontent\u002Fimages\u002Fski_jump_1440x960.heic\")) { image in\n        image.resizable() \u002F\u002F Control layout like SwiftUI.AsyncImage, you must use this modifier or the view will use the image bitmap size\n    } placeholder: {\n            Rectangle().foregroundColor(.gray)\n    }\n    \u002F\u002F Supports options and context, like `.delayPlaceholder` to show placeholder only when error\n    .onSuccess { image, data, cacheType in\n        \u002F\u002F Success\n        \u002F\u002F Note: Data exist only when queried from disk cache or network. Use `.queryMemoryData` if you really need data\n    }\n    .indicator(.activity) \u002F\u002F Activity Indicator\n    .transition(.fade(duration: 0.5)) \u002F\u002F Fade Transition with duration\n    .scaledToFit()\n    .frame(width: 300, height: 300, alignment: .center)\n}\n```\n\nNote: This `WebImage` using `Image` for internal implementation, which is the best compatible for SwiftUI layout and animation system. But unlike SwiftUI's `Image` which does not support animated image or vector image, `WebImage` supports animated image as well (by defaults from v2.0.0).\n\nHowever, The `WebImage` animation provide simple common use case, so it's still recommend to use `AnimatedImage` for advanced controls like progressive animation rendering, or vector image rendering.\n\n```swift\n@State var isAnimating: Bool = true\nvar body: some View {\n    WebImage(url: URL(string: \"https:\u002F\u002Fraw.githubusercontent.com\u002Fliyong03\u002FYLGIFImage\u002Fmaster\u002FYLGIFImageDemo\u002FYLGIFImageDemo\u002Fjoy.gif\"), isAnimating: $isAnimating)) \u002F\u002F Animation Control, supports dynamic changes\n    \u002F\u002F The initial value of binding should be true\n    .customLoopCount(1) \u002F\u002F Custom loop count\n    .playbackRate(2.0) \u002F\u002F Playback speed rate\n    .playbackMode(.bounce) \u002F\u002F Playback normally to the end, then reversely back to the start\n    \u002F\u002F `WebImage` supports advanced control just like `AnimatedImage`, but without the progressive animation support\n}\n```\n\nNote: For indicator, you can custom your own as well. For example, iOS 14\u002FwatchOS 7 introduce the new `ProgressView`, which can be easily used via:\n\n```swift\nWebImage(url: url)\n.indicator(.activity)\n```\n\nor you can just write like:\n\n```swift\nWebImage(url: url)\n.indicator {\n    Indicator { _, _ in\n        ProgressView()\n    }\n}\n```\n\n### Using `AnimatedImage` to play animation\n\n- [x] Supports network image as well as local data and bundle image\n- [x] Supports animated image format as well as vector image format\n- [x] Supports animated progressive image loading (like web browser)\n- [x] Supports animation control using the SwiftUI Binding\n- [x] Supports indicator and transition, powered by SDWebImage and Core Animation\n- [x] Supports advanced control like loop count, playback rate, buffer size, runloop mode, etc\n- [x] Supports coordinate with native UIKit\u002FAppKit view\n\n```swift\nvar body: some View {\n    Group {\n        AnimatedImage(url: URL(string: \"https:\u002F\u002Fraw.githubusercontent.com\u002Fliyong03\u002FYLGIFImage\u002Fmaster\u002FYLGIFImageDemo\u002FYLGIFImageDemo\u002Fjoy.gif\"), placeholderImage: .init(systemName: \"photo\")) \u002F\u002F Placeholder Image\n        \u002F\u002F Supports options and context, like `.progressiveLoad` for progressive animation loading\n        .onFailure { error in\n            \u002F\u002F Error\n        }\n        .resizable() \u002F\u002F Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size\n        .indicator(.activity) \u002F\u002F Activity Indicator\n        .transition(.fade) \u002F\u002F Fade Transition\n        .scaledToFit() \u002F\u002F Attention to call it on AnimatedImage, but not `some View` after View Modifier (Swift Protocol Extension method is static dispatched)\n        \n        \u002F\u002F Supports SwiftUI ViewBuilder placeholder as well\n        AnimatedImage(url: url) {\n            Circle().foregroundColor(.gray)\n        }\n        \n        \u002F\u002F Data\n        AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: \"\u002Ftmp\u002Ffoo.webp\")))\n        .customLoopCount(1) \u002F\u002F Custom loop count\n        .playbackRate(2.0) \u002F\u002F Playback speed rate\n        \n        \u002F\u002F Bundle (not Asset Catalog)\n        AnimatedImage(name: \"animation1.gif\", isAnimating: $isAnimating) \u002F\u002F Animation control binding\n        .maxBufferSize(.max)\n        .onViewUpdate { view, context in \u002F\u002F Advanced native view coordinate\n            \u002F\u002F AppKit tooltip for mouse hover\n            view.toolTip = \"Mouseover Tip\"\n            \u002F\u002F UIKit advanced content mode\n            view.contentMode = .topLeft\n            \u002F\u002F Coordinator, used for Cocoa Binding or Delegate method\n            let coordinator = context.coordinator\n        }\n    }\n}\n```\n\nNote: `AnimatedImage` supports both image url or image data for animated image format. Which use the SDWebImage's [Animated ImageView](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage\u002Fwiki\u002FAdvanced-Usage#animated-image-50) for internal implementation. Pay attention that since this base on UIKit\u002FAppKit representable, some advanced SwiftUI layout and animation system may not work as expected. You may need UIKit\u002FAppKit and Core Animation to modify the native view.\n\nNote: `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\u002FAppKit component and animation. If you find ambiguity, use full type declaration instead of the dot expression syntax.\n\nNote: 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\u002FAppKit API for rescue.\n\n```swift\n\n\u002F\u002F Using UIKit components\nvar body: some View {\n    AnimatedImage(name: \"animation2.gif\") \n    .indicator(SDWebImageProgressIndicator.default) \u002F\u002F UIKit indicator component\n    .transition(SDWebImageTransition.flipFromLeft) \u002F\u002F UIKit animation transition\n}\n\n\u002F\u002F Using SwiftUI components\nvar body: some View {\n    AnimatedImage(name: \"animation2.gif\")\n    .indicator(Indicator.progress) \u002F\u002F SwiftUI indicator component\n    .transition(AnyTransition.flipFromLeft) \u002F\u002F SwiftUI animation transition\n}\n```\n\n### Which View to choose\n\nWhy we have two different View types here, is because of current SwiftUI limit. But we're aimed to provide best solution for all use cases.\n\nIf you don't need animated image, prefer to use `WebImage` firstly. Which behaves the seamless as built-in SwiftUI View. If SwiftUI works, it works. If SwiftUI doesn't work, it either :)\n\nIf you need simple animated image, use `WebImage`. Which provide the basic animated image support. But it does not support progressive animation rendering, nor vector image, if you don't care about this.\n\nIf you need powerful animated image, `AnimatedImage` is the one to choose. Remember it supports static image as well, you don't need to check the format, just use as it. Also, some powerful feature like UIKit\u002FAppKit tint color, vector image, symbol image configuration, tvOS layered image, only available in `AnimatedImage` but not currently in SwfitUI.\n\nBut, because `AnimatedImage` use `UIViewRepresentable` and driven by UIKit, currently there may be some small incompatible issues between UIKit and SwiftUI layout and animation system, or bugs related to SwiftUI itself. We try our best to match SwiftUI behavior, and provide the same API as `WebImage`, which make it easy to switch between these two types if needed.\n\n### Use `ImageManager` for your own View type\n\nThe `ImageManager` is a class which conforms to Combine's [ObservableObject](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fcombine\u002Fobservableobject) protocol. Which is the core fetching data source of `WebImage` we provided.\n\nFor advanced use case, like loading image into the complicated View graph which you don't want to use `WebImage`. You can directly bind your own View type with the Manager.\n\nIt looks familiar like `SDWebImageManager`, but it's built for SwiftUI world, which provide the Source of Truth for loading images. You'd better use SwiftUI's `@ObservedObject` to bind each single manager instance for your View instance, which automatically update your View's body when image status changed.\n\n```swift\nstruct MyView : View {\n    @ObservedObject var imageManager = ImageManager()\n    var body: some View {\n        \u002F\u002F Your custom complicated view graph\n        Group {\n            if imageManager.image != nil {\n                Image(uiImage: imageManager.image!)\n            } else {\n                Rectangle().fill(Color.gray)\n            }\n        }\n        \u002F\u002F Trigger image loading when appear\n        .onAppear { self.imageManager.load(url: url) }\n        \u002F\u002F Cancel image loading when disappear\n        .onDisappear { self.imageManager.cancel() }\n    }\n}\n```\n\n### Customization and configuration setup\n\nThis framework is based on SDWebImage, which supports advanced customization and configuration to meet different users' demand.\n\nYou can register multiple coder plugins for external image format. You can register multiple caches (different paths and config), multiple loaders (URLSession and Photos URLs). You can control the cache expiration date, size, download priority, etc. All in our [wiki](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage\u002Fwiki\u002F).\n\nThe best place to put these setup code for SwiftUI App, it's the `AppDelegate.swift`:\n\n```swift\nfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n    \u002F\u002F Add WebP\u002FSVG\u002FPDF support\n    SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)\n    SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared)\n    SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)\n    SDImageCodersManager.shared.addCoder(SDImagePDFCoder.shared)\n    \n    \u002F\u002F Add default HTTP header\n    SDWebImageDownloader.shared.setValue(\"image\u002Fwebp,image\u002Fapng,image\u002F*,*\u002F*;q=0.8\", forHTTPHeaderField: \"Accept\")\n    \n    \u002F\u002F Add multiple caches\n    let cache = SDImageCache(namespace: \"tiny\")\n    cache.config.maxMemoryCost = 100 * 1024 * 1024 \u002F\u002F 100MB memory\n    cache.config.maxDiskSize = 50 * 1024 * 1024 \u002F\u002F 50MB disk\n    SDImageCachesManager.shared.addCache(cache)\n    SDWebImageManager.defaultImageCache = SDImageCachesManager.shared\n    \n    \u002F\u002F Add multiple loaders with Photos Asset support\n    SDImageLoadersManager.shared.addLoader(SDImagePhotosLoader.shared)\n    SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared\n    return true\n}\n```\n\nFor more information, it's really recommended to check our demo, to learn detailed API usage. You can also have a check at the latest API documentation, for advanced usage.\n\n## Documentation\n\n+ [SDWebImageSwiftUI API documentation](https:\u002F\u002Fsdwebimage.github.io\u002Fdocumentation\u002Fsdwebimageswiftui\u002F)\n+ [SDWebImage API documentation](https:\u002F\u002Fsdwebimage.github.io\u002F)\n\n## FAQ\n\n### Common Problems\n\n#### Using WebImage\u002FAnimatedImage in List\u002FLazyStack\u002FLazyGrid and ForEach\n\nSwiftUI has a known behavior(bug?) when using stateful view in `List\u002FLazyStack\u002FLazyGrid`.\nOnly the **Top Level** view can hold its own `@State\u002F@StateObject`, but the sub structure will lose state when scroll out of screen.\nHowever, WebImage\u002FAnimated is both stateful. To ensure the state keep in sync even when scroll out of screen. you may use some tricks.\n\nSee more: https:\u002F\u002Ftwitter.com\u002Ffatbobman\u002Fstatus\u002F1572507700436807683?s=21&t=z4FkAWTMvjsgL-wKdJGreQ\n\nIn short, it's not recommanded to do so:\n\n```swift\nstruct ContentView {\n    @State var imageURLs: [String]\n    var body: some View {\n        List {\n            ForEach(imageURLs, id: \\.self) { url in\n                VStack {\n                    WebImage(url) \u002F\u002F The top level is `VStack`\n                }\n            }\n        }\n    }\n}\n```\n\ninstead, using this approach:\n\n```swift\nstruct ContentView {\n    struct BodyView {\n        @State var url: String\n        var body: some View {\n            VStack {\n                WebImage(url)\n            }\n        }\n    }\n    @State var imageURLs: [String]\n    var body: some View {\n        List {\n            ForEach(imageURLs, id: \\.self) { url in\n                BodyView(url: url)\n            }\n        }\n    }\n}\n```\n\n#### Using Image\u002FWebImage\u002FAnimatedImage in Button\u002FNavigationLink\n\nSwiftUI's `Button` apply overlay to its content (except `Text`) by default, this is common mistake to write code like this, which cause strange behavior:\n\n```swift\n\u002F\u002F Wrong\nButton(action: {\n    \u002F\u002F Clicked\n}) {\n    WebImage(url: url)\n}\n\u002F\u002F NavigationLink create Button implicitly\nNavigationView {\n    NavigationLink(destination: Text(\"Detail view here\")) {\n        WebImage(url: url)\n    }\n}\n```\n\nInstead, you must override the `.buttonStyle` to use the plain style, or the `.renderingMode` to use original mode. You can also use the `.onTapGesture` modifier for touch handling. See [How to disable the overlay color for images inside Button and NavigationLink](https:\u002F\u002Fwww.hackingwithswift.com\u002Fquick-start\u002Fswiftui\u002Fhow-to-disable-the-overlay-color-for-images-inside-button-and-navigationlink)\n\n```swift\n\u002F\u002F Correct\nButton(action: {\n    \u002F\u002F Clicked\n}) {\n    WebImage(url: url)\n}\n.buttonStyle(PlainButtonStyle())\n\u002F\u002F Or\nNavigationView {\n    NavigationLink(destination: Text(\"Detail view here\")) {\n        WebImage(url: url)\n        .renderingMode(.original)\n    }\n}\n```\n\n#### Render vector image (SVG\u002FPDF) with tint color\n\nBoth `WebImage\u002FAnimatedImage` supports to render the vector image, by using the `SVG\u002FPDF` external coders. However they are different internally.\n\n+ `AnimatedImage`: use tech from Apple's symbol image and vector drawing, supports dynamic size changes without lossing details. And it use UIKit\u002FAppKit based implementation and APIs. If you want, pass `.context(.imageThumbnailPixelSize: size)` to use bitmap rendering and get more pixels.\n+ `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.\n\nFor bitmap rendering, you can also tint the SVG\u002FPDF icons with custom colors (like symbol images), use the `.renderingMode(.template)` and `.tint(:)` or `.foregroundColor(:)` modifier, which matches `SwiftUI.Image` behavior.\n\n+ WebImage\n\n```swift\nvar body: some View {\n    WebImage(url: URL(string: \"https:\u002F\u002Fdev.w3.org\u002FSVG\u002Ftools\u002Fsvgweb\u002Fsamples\u002Fsvg-files\u002Fw3c.svg\"))\n    .resizable()\n    .renderingMode(.template)\n    .foregroundColor(.red) \u002F\u002F or `.tint(:)`, `.accentColor(:)`\n    .scaledToFit()\n}\n```\n\n+ AnimatedImage\n\n```swift\nvar body: some View {\n    AnimatedImage(url: URL(string: \"https:\u002F\u002Fdev.w3.org\u002FSVG\u002Ftools\u002Fsvgweb\u002Fsamples\u002Fsvg-files\u002Fw3c.svg\"), context: [.imageThumbnailPixelSize : CGSize(width: 100, height: 100)])\n    .resizable()\n    .renderingMode(.template)\n    \u002F\u002F seems `.foregroundColor(:)` does effect `UIView.tintColor`, use `tint(:)` or `.accentColor(:)` instead.\n    \u002F\u002F Or you can use `onViewCreate(:)` to get native `SDAnimatedImageView` and set `tintColor` (AppKit use `contentTintColor`)\n    .tint(.red)\n    .scaledToFit()\n}\n```\n\nSee more: [Configuring and displaying symbol images in your UI](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fuikit\u002Fuiimage\u002Fconfiguring_and_displaying_symbol_images_in_your_ui?language=objc)\n\n#### Using with external loaders\u002Fcaches\u002Fcoders\n\nSDWebImage itself, supports many custom loaders (like [Firebase Storage](https:\u002F\u002Fgithub.com\u002Ffirebase\u002FFirebaseUI-iOS) and [PhotosKit](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImagePhotosPlugin)), caches (like [YYCache](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageYYPlugin) and [PINCache](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImagePINPlugin)), and coders (like [WebP](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageWebPCoder) and [AVIF](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageAVIFCoder), even [Lottie](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImageLottieCoder)).\n\nHere is the tutorial to setup these external components with SwiftUI environment.\n\n##### Setup external SDKs\n\nYou can put the setup code inside your SwiftUI `App.init()` method.\n\n```swift\n@main\nstruct MyApp: App {\n    \n    init() {\n        \u002F\u002F Custom Firebase Storage Loader\n        FirebaseApp.configure()\n        SDImageLoadersManager.shared.loaders = [FirebaseUI.StorageImageLoader.shared]\n        SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared\n        \u002F\u002F WebP support\n        SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)\n        \u002F\u002F AVIF support\n        SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared)\n    }\n    \n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n```\n\nor, if your App have complicated `AppDelegate` class, put setup code there:\n\n```swift\nclass AppDelegate: NSObject, UIApplicationDelegate {\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {\n        SDImageCachesManager.shared.caches = [YYCache(name: \"default\")]\n        SDWebImageManager.defaultImageCache = SDImageCachesManager.shared\n        return true\n    }\n}\n\n@main\nstruct MyApp: App {\n    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate\n\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n```\n\n##### Use external SDKs\n\nFor some of custom loaders, you need to create the `URL` struct with some special APIs, so that SDWebImage can retrieve the context from other SDKs, like:\n\n+ FirebaseStorage\n\n```swift\nlet storageRef: StorageReference\nlet storageURL = NSURL.sd_URL(with: storageRef) as URL?\n\u002F\u002F Or via convenience extension\nlet storageURL = storageRef.sd_URLRepresentation\n```\n\n+ PhotosKit\n\n```swift\nlet asset: PHAsset\nlet photosURL = NSURL.sd_URL(with: asset) as URL?\n\u002F\u002F Or via convenience extension\nlet photosURL = asset.sd_URLRepresentation\n```\n\nFor some of custom coders, you need to request the image with some options to control the behavior, like Vector Images SVG\u002FPDF. Because SwiftUI.Image or WebImage does not supports vector graph at all.\n\n+ SVG\u002FPDF Coder\n\n```swift\nlet vectorURL: URL? \u002F\u002F URL to SVG or PDF\nWebImage(url: vectorURL, context: [.imageThumbnailPixelSize: CGSize(width: 100, height: 100)])\n```\n\n+ Lottie Coder\n\n```swift\nlet lottieURL: URL? \u002F\u002F URL to Lottie.json\nWebImage(url: lottieURL, isAnimating: $isAnimating)\n```\n\nFor caches, you actually don't need to worry about anything. It just works after setup.\n\n#### Using for backward deployment and weak linking SwiftUI\n\nSDWebImageSwiftUI supports to use when your App Target has a deployment target version less than iOS 14\u002FmacOS 11\u002FtvOS 14\u002FwatchOS 7. Which will weak linking of SwiftUI(Combine) to allows writing code with available check at runtime.\n\nTo use backward deployment, you have to do the follow things:\n\n##### Add weak linking framework\n\nAdd `-weak_framework SwiftUI -weak_framework Combine` in your App Target's `Other Linker Flags` build setting. You can also do this using Xcode's `Optional Framework` checkbox, there have the same effect.\n\nYou should notice that all the third party SwiftUI frameworks should have this build setting as well, not only just SDWebImageSwiftUI. Or when running on iOS 12 device, it will trigger the runtime dyld error on startup.\n\n##### Backward deployment on iOS 12.1-\n\nFor deployment target version below iOS 12.2 (The first version which Swift 5 Runtime bundled in iOS system), you have to change the min deployment target version of SDWebImageSwiftUI. This may take some side effect on compiler's optimization and trigger massive warnings for some frameworks.\n\nHowever, for iOS 12.2+, you can still keep the min deployment target version to iOS 14, no extra warnings or performance slow down for iOS 14 client.\n\nBecause Swift use the min deployment target version to detect whether to link the App bundled Swift runtime, or the System built-in one (`\u002Fusr\u002Flib\u002Fswift\u002FlibswiftCore.dylib`).\n\n+ For CocoaPods user, you can change the min deployment target version in the Podfile via post installer:\n\n```ruby\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' # version you need\n    end\n  end\nend\n```\n\n+ For Carthage user, you can use `carthage update --no-build` to download the dependency, then change the Xcode Project's deployment target version and build the binary framework.\n\n+ For SwiftPM user, you have to use the local dependency (with the Git submodule) to change the deployment target version.\n\n##### Backward deployment on iOS 12.2+\n\n+ For Carthage user, the built binary framework will use [Library Evolution](https:\u002F\u002Fswift.org\u002Fblog\u002Fabi-stability-and-more\u002F) to support for backward deployment.\n\n+ For CocoaPods user, you can skip the platform version validation in Podfile with:\n\n```ruby\nplatform :ios, '14.0' # This does not effect your App Target's deployment target version, just a hint for CocoaPods\n```\n\n+ For SwiftPM user, SwiftPM does not support weak linking nor Library Evolution, so it can not deployment to iOS 12+ user without changing the min deployment target.\n    \n##### Add available annotation\n\nAdd **all the SwiftUI code** with the available annotation and runtime check, like this:\n\n```swift\n\u002F\u002F AppDelegate.swift\nfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n    \u002F\u002F ...\n    if #available(iOS 14, *) {\n        window.rootViewController = UIHostingController(rootView: ContentView())\n    } else {\n        window.rootViewController = ViewController()\n    }\n    \u002F\u002F ...\n}\n\n\u002F\u002F ViewController.swift\nclass ViewController: UIViewController {\n    var label: UILabel = UILabel()\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        view.backgroundColor = .white\n        view.addSubview(label)\n        label.text = \"Hello World iOS 12!\"\n        label.sizeToFit()\n        label.center = view.center\n    }\n}\n\n\u002F\u002F ContentView.swift\n@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)\nstruct ContentView : View {\n    var body: some View {\n        Group {\n            Text(\"Hello World iOS 14!\")\n            WebImage(url: URL(string: \"https:\u002F\u002Fi.loli.net\u002F2019\u002F09\u002F24\u002FrX2RkVWeGKIuJvc.jpg\"))\n        }\n    }\n}\n```\n\n## Demo\n\nTo run the example using SwiftUI, following the steps:\n\n1. Open `SDWebImageSwiftUI.xcworkspace`, wait for SwiftPM finishing downloading the test dependency.\n2. Choose `SDWebImageSwiftUIDemo` (or other platforms) scheme and run the demo application.\n\nNote: The `Podfile` here is because history we use CocoaPods to integrate libs into Demo, but now we use SPM.\n\nSince SwiftUI is aimed to support all Apple platforms, our demo does this as well, one codebase including:\n\n+ iOS (iPhone\u002FiPad\u002FMac Catalyst)\n+ macOS\n+ tvOS\n+ watchOS\n+ visionOS\n\nDemo Tips:\n\n1. Use `Switch` (right-click on macOS\u002Ftap on watchOS) to switch between `WebImage` and `AnimatedImage`.\n2. Use `Reload` (right-click on macOS\u002Fbutton on watchOS) to clear cache.\n3. Use `Swipe Left` (menu button on tvOS) to delete one image url from list.\n4. Pinch gesture (Digital Crown on watchOS, play button on tvOS) to zoom-in detail page image.\n5. Clear cache and go to detail page to see progressive loading.\n\n## Test\n\nSDWebImageSwiftUI has Unit Test to increase code quality. For SwiftUI, there are no official Unit Test solution provided by Apple.\n\nHowever, since SwiftUI is State-Based and Attributed-Implemented layout system, there are open source projects who provide the solution:\n\n+ [ViewInspector](https:\u002F\u002Fgithub.com\u002Fnalexn\u002FViewInspector): Inspect View's runtime attribute value (like `.frame` modifier, `.image` value). We use this to test `AnimatedImage` and `WebImage`. It also allows the inspect to native UIView\u002FNSView.\n\nTo run the test:\n\n1. Run `pod install` on root directory to install the dependency.\n2. Open `SDWebImageSwiftUI.xcworkspace`, wait for SwiftPM finishing downloading the test dependency.\n3. Choose `SDWebImageSwiftUITests` scheme and start testing.\n\nWe've already setup the CI pipeline, each PR will run the test case and upload the test report to [codecov](https:\u002F\u002Fcodecov.io\u002Fgh\u002FSDWebImage\u002FSDWebImageSwiftUI).\n\n## Screenshot\n\n+ iOS Demo\n\n\u003Cimg src='https:\u002F\u002Fraw.githubusercontent.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Fmaster\u002FExample\u002FScreenshot\u002FDemo-iOS.jpg' height=960 \u002F>\n\n+ macOS Demo\n\n\u003Cimg src='https:\u002F\u002Fraw.githubusercontent.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Fmaster\u002FExample\u002FScreenshot\u002FDemo-macOS.jpg' width=960 \u002F>\n\n+ tvOS Demo\n\n\u003Cimg src='https:\u002F\u002Fraw.githubusercontent.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Fmaster\u002FExample\u002FScreenshot\u002FDemo-tvOS.jpg' width=960 \u002F>\n\n+ watchOS Demo\n\n\u003Cimg src='https:\u002F\u002Fraw.githubusercontent.com\u002FSDWebImage\u002FSDWebImageSwiftUI\u002Fmaster\u002FExample\u002FScreenshot\u002FDemo-watchOS.jpg' width=480 \u002F>\n\n## Extra Notes\n\nBesides all above things, this project can also ensure the following function available on Swift platform for SDWebImage itself.\n\n+ SwiftUI compatibility\n+ Swift Package Manager integration\n+ Swift source code compatibility and Swifty\n\nWhich means, this project is one core use case and downstream dependency, which driven SDWebImage itself future development.\n\n## Author\n\n[DreamPiggy](https:\u002F\u002Fgithub.com\u002Fdreampiggy)\n\n## Thanks\n\n- [SDWebImage](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002FSDWebImage)\n- [libwebp](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002Flibwebp-Xcode)\n- [libavif](https:\u002F\u002Fgithub.com\u002FSDWebImage\u002Flibavif-Xcode)\n- [Kingfisher](https:\u002F\u002Fgithub.com\u002Fonevcat\u002FKingfisher)\n- [SwiftUIX](https:\u002F\u002Fgithub.com\u002FSwiftUIX\u002FSwiftUIX)\n- [Espera](https:\u002F\u002Fgithub.com\u002FJagCesar\u002FEspera)\n- [SwiftUI-Introspect](https:\u002F\u002Fgithub.com\u002Fsiteline\u002FSwiftUI-Introspect)\n- [ViewInspector](https:\u002F\u002Fgithub.com\u002Fnalexn\u002FViewInspector)\n- [SwiftUIBackports](https:\u002F\u002Fgithub.com\u002Fshaps80\u002FSwiftUIBackports)\n\n## License\n\nSDWebImageSwiftUI is available under the MIT license. See the LICENSE file for more info.\n\n\n","SDWebImageSwiftUI 是一个基于 SDWebImage 的 SwiftUI 图像加载框架。它提供了异步图像加载、内存\u002F磁盘缓存以及动画图像播放等功能，支持多种图像格式如 GIF、APNG 和 WebP 等。该框架设计了符合 SwiftUI 指南的视图结构，使得熟悉 `Image` 的开发者可以轻松上手 `WebImage` 和 `AnimatedImage`。SDWebImageSwiftUI 适用于 iOS、macOS、tvOS 和 watchOS 平台上的应用开发，尤其适合需要高效处理网络图片和动画的应用场景。此外，从 v3.0.0 版本开始，还支持 visionOS 平台。","2026-06-11 03:10:38","top_language"]