Skip to content

Commit 0897944

Browse files
authored
Merge pull request #7 from SDWebImage/feature_image_method
Feature support the Image struct method on `WebImage` and `AnimatedImage`
2 parents a37f209 + 5d949dc commit 0897944

File tree

9 files changed

+295
-45
lines changed

9 files changed

+295
-45
lines changed

Example/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PODS:
22
- SDWebImage (5.1.0):
33
- SDWebImage/Core (= 5.1.0)
44
- SDWebImage/Core (5.1.0)
5-
- SDWebImageSwiftUI (0.1.0):
5+
- SDWebImageSwiftUI (0.1.1):
66
- SDWebImage (~> 5.1)
77

88
DEPENDENCIES:
@@ -18,7 +18,7 @@ EXTERNAL SOURCES:
1818

1919
SPEC CHECKSUMS:
2020
SDWebImage: fb387001955223213dde14bc08c8b73f371f8d8f
21-
SDWebImageSwiftUI: 22254f3ced4f056602cd8167b64106ab6419c6e6
21+
SDWebImageSwiftUI: fa0b13b16a92985532cd13931b88aea4ff7efb0b
2222

2323
PODFILE CHECKSUM: 146734166216dd8fc1597433cc675999454ed4b2
2424

Example/SDWebImageSwiftUIDemo/ContentView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ struct ContentView: View {
1515
var body: some View {
1616
VStack {
1717
WebImage(url: URL(string: "https://nokiatech.github.io/heif/content/images/ski_jump_1440x960.heic"))
18+
.resizable()
1819
.scaledToFit()
1920
.frame(width: CGFloat(300), height: CGFloat(300), alignment: .center)
2021
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"), options: [.progressiveLoad])
22+
.resizable()
2123
.scaledToFill()
2224
.frame(width: CGFloat(400), height: CGFloat(300), alignment: .center)
2325
}

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SDWebImageSwiftUI.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
326E480A23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
11+
326E480B23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
12+
326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
13+
326E480D23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
1014
32C43DE622FD54CD00BE87F5 /* SDWebImageSwiftUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C43DE422FD54CD00BE87F5 /* SDWebImageSwiftUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
1115
32C43DEA22FD577300BE87F5 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32C43DE922FD577300BE87F5 /* SDWebImage.framework */; };
1216
32C43DEB22FD577300BE87F5 /* SDWebImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 32C43DE922FD577300BE87F5 /* SDWebImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -85,6 +89,7 @@
8589
/* End PBXCopyFilesBuildPhase section */
8690

8791
/* Begin PBXFileReference section */
92+
326E480923431C0F00C633E9 /* ImageViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewWrapper.swift; sourceTree = "<group>"; };
8893
32C43DCC22FD540D00BE87F5 /* SDWebImageSwiftUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageSwiftUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8994
32C43DDC22FD54C600BE87F5 /* ImageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageManager.swift; sourceTree = "<group>"; };
9095
32C43DDE22FD54C600BE87F5 /* WebImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebImage.swift; sourceTree = "<group>"; };
@@ -174,6 +179,7 @@
174179
32C43DDE22FD54C600BE87F5 /* WebImage.swift */,
175180
32C43DDF22FD54C600BE87F5 /* AnimatedImage.swift */,
176181
32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */,
182+
326E480923431C0F00C633E9 /* ImageViewWrapper.swift */,
177183
);
178184
path = Classes;
179185
sourceTree = "<group>";
@@ -385,6 +391,7 @@
385391
files = (
386392
32C43E1722FD583700BE87F5 /* WebImage.swift in Sources */,
387393
32C43E3222FD5DE100BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
394+
326E480A23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
388395
32C43E1622FD583700BE87F5 /* ImageManager.swift in Sources */,
389396
32C43E1822FD583700BE87F5 /* AnimatedImage.swift in Sources */,
390397
);
@@ -396,6 +403,7 @@
396403
files = (
397404
32C43E1A22FD583700BE87F5 /* WebImage.swift in Sources */,
398405
32C43E3322FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
406+
326E480B23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
399407
32C43E1922FD583700BE87F5 /* ImageManager.swift in Sources */,
400408
32C43E1B22FD583700BE87F5 /* AnimatedImage.swift in Sources */,
401409
);
@@ -407,6 +415,7 @@
407415
files = (
408416
32C43E1D22FD583800BE87F5 /* WebImage.swift in Sources */,
409417
32C43E3422FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
418+
326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
410419
32C43E1C22FD583800BE87F5 /* ImageManager.swift in Sources */,
411420
32C43E1E22FD583800BE87F5 /* AnimatedImage.swift in Sources */,
412421
);
@@ -418,6 +427,7 @@
418427
files = (
419428
32C43E2022FD583800BE87F5 /* WebImage.swift in Sources */,
420429
32C43E3522FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
430+
326E480D23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
421431
32C43E1F22FD583800BE87F5 /* ImageManager.swift in Sources */,
422432
32C43E2122FD583800BE87F5 /* AnimatedImage.swift in Sources */,
423433
);

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 132 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ final class AnimatedImageModel : ObservableObject {
2020
// Layout Binding Object
2121
final class AnimatedImageLayout : ObservableObject {
2222
@Published var contentMode: ContentMode = .fill
23+
@Published var aspectRatio: CGFloat?
24+
@Published var renderingMode: Image.TemplateRenderingMode?
25+
@Published var interpolation: Image.Interpolation?
26+
@Published var antialiased: Bool = false
2327
}
2428

2529
// View
@@ -31,53 +35,115 @@ public struct AnimatedImage : ViewRepresentable {
3135
var webContext: [SDWebImageContextOption : Any]? = nil
3236

3337
#if os(macOS)
34-
public typealias NSViewType = SDAnimatedImageView
38+
public typealias NSViewType = AnimatedImageViewWrapper
3539
#else
36-
public typealias UIViewType = SDAnimatedImageView
40+
public typealias UIViewType = AnimatedImageViewWrapper
3741
#endif
3842

3943
#if os(macOS)
40-
public func makeNSView(context: NSViewRepresentableContext<AnimatedImage>) -> SDAnimatedImageView {
44+
public func makeNSView(context: NSViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
4145
makeView(context: context)
4246
}
4347

44-
public func updateNSView(_ nsView: SDAnimatedImageView, context: NSViewRepresentableContext<AnimatedImage>) {
48+
public func updateNSView(_ nsView: AnimatedImageViewWrapper, context: NSViewRepresentableContext<AnimatedImage>) {
4549
updateView(nsView, context: context)
4650
}
4751
#else
48-
public func makeUIView(context: UIViewRepresentableContext<AnimatedImage>) -> SDAnimatedImageView {
52+
public func makeUIView(context: UIViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
4953
makeView(context: context)
5054
}
5155

52-
public func updateUIView(_ uiView: SDAnimatedImageView, context: UIViewRepresentableContext<AnimatedImage>) {
56+
public func updateUIView(_ uiView: AnimatedImageViewWrapper, context: UIViewRepresentableContext<AnimatedImage>) {
5357
updateView(uiView, context: context)
5458
}
5559
#endif
5660

57-
func makeView(context: ViewRepresentableContext<AnimatedImage>) -> SDAnimatedImageView {
58-
SDAnimatedImageView()
61+
func makeView(context: ViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
62+
AnimatedImageViewWrapper()
5963
}
6064

61-
func updateView(_ view: SDAnimatedImageView, context: ViewRepresentableContext<AnimatedImage>) {
62-
view.image = imageModel.image
65+
func updateView(_ view: AnimatedImageViewWrapper, context: ViewRepresentableContext<AnimatedImage>) {
66+
view.wrapped.image = imageModel.image
6367
if let url = imageModel.url {
64-
view.sd_setImage(with: url, placeholderImage: view.image, options: webOptions, context: webContext)
68+
view.wrapped.sd_setImage(with: url, placeholderImage: nil, options: webOptions, context: webContext)
6569
}
6670

71+
layoutView(view, context: context)
72+
}
73+
74+
func layoutView(_ view: AnimatedImageViewWrapper, context: ViewRepresentableContext<AnimatedImage>) {
75+
// AspectRatio
76+
if let _ = imageLayout.aspectRatio {
77+
// TODO: Needs layer transform and geometry calculation
78+
}
79+
80+
// ContentMode
6781
switch imageLayout.contentMode {
6882
case .fit:
6983
#if os(macOS)
70-
view.imageScaling = .scaleProportionallyUpOrDown
84+
view.wrapped.imageScaling = .scaleProportionallyUpOrDown
7185
#else
72-
view.contentMode = .scaleAspectFit
86+
view.wrapped.contentMode = .scaleAspectFit
7387
#endif
7488
case .fill:
7589
#if os(macOS)
76-
view.imageScaling = .scaleAxesIndependently
90+
view.wrapped.imageScaling = .scaleAxesIndependently
7791
#else
78-
view.contentMode = .scaleToFill
92+
view.wrapped.contentMode = .scaleToFill
7993
#endif
8094
}
95+
96+
// RenderingMode
97+
if let renderingMode = imageLayout.renderingMode {
98+
switch renderingMode {
99+
case .template:
100+
#if os(macOS)
101+
view.wrapped.image?.isTemplate = true
102+
#else
103+
view.wrapped.image = view.wrapped.image?.withRenderingMode(.alwaysTemplate)
104+
#endif
105+
case .original:
106+
#if os(macOS)
107+
view.wrapped.image?.isTemplate = false
108+
#else
109+
view.wrapped.image = view.wrapped.image?.withRenderingMode(.alwaysOriginal)
110+
#endif
111+
@unknown default:
112+
// Future cases, not implements
113+
break
114+
}
115+
}
116+
117+
// Interpolation
118+
if let interpolation = imageLayout.interpolation {
119+
switch interpolation {
120+
case .high:
121+
view.interpolationQuality = .high
122+
case .medium:
123+
view.interpolationQuality = .medium
124+
case .low:
125+
view.interpolationQuality = .low
126+
case .none:
127+
view.interpolationQuality = .none
128+
@unknown default:
129+
// Future cases, not implements
130+
break
131+
}
132+
} else {
133+
view.interpolationQuality = .default
134+
}
135+
136+
// Antialiased
137+
view.shouldAntialias = imageLayout.antialiased
138+
139+
// Display
140+
#if os(macOS)
141+
view.needsLayout = true
142+
view.needsDisplay = true
143+
#else
144+
view.setNeedsLayout()
145+
view.setNeedsDisplay()
146+
#endif
81147
}
82148

83149
public func image(_ image: SDAnimatedImage?) -> Self {
@@ -90,15 +156,49 @@ public struct AnimatedImage : ViewRepresentable {
90156
return self
91157
}
92158

93-
public func scaledToFit() -> Self {
94-
imageLayout.contentMode = .fit
159+
public func resizable(
160+
capInsets: EdgeInsets = EdgeInsets(),
161+
resizingMode: Image.ResizingMode = .stretch) -> AnimatedImage
162+
{
163+
return self
164+
}
165+
166+
public func renderingMode(_ renderingMode: Image.TemplateRenderingMode?) -> AnimatedImage {
167+
imageLayout.renderingMode = renderingMode
168+
return self
169+
}
170+
171+
public func interpolation(_ interpolation: Image.Interpolation) -> AnimatedImage {
172+
imageLayout.interpolation = interpolation
173+
return self
174+
}
175+
176+
public func antialiased(_ isAntialiased: Bool) -> AnimatedImage {
177+
imageLayout.antialiased = isAntialiased
95178
return self
96179
}
97180

98-
public func scaledToFill() -> Self {
99-
imageLayout.contentMode = .fill
181+
public func aspectRatio(_ aspectRatio: CGFloat? = nil, contentMode: ContentMode) -> AnimatedImage {
182+
imageLayout.aspectRatio = aspectRatio
183+
imageLayout.contentMode = contentMode
100184
return self
101185
}
186+
187+
public func aspectRatio(_ aspectRatio: CGSize, contentMode: ContentMode) -> AnimatedImage {
188+
var ratio: CGFloat?
189+
if aspectRatio.width > 0 && aspectRatio.height > 0 {
190+
ratio = aspectRatio.width / aspectRatio.height
191+
}
192+
return self.aspectRatio(ratio, contentMode: contentMode)
193+
}
194+
195+
public func scaledToFit() -> AnimatedImage {
196+
self.aspectRatio(nil, contentMode: .fit)
197+
}
198+
199+
public func scaledToFill() -> AnimatedImage {
200+
self.aspectRatio(nil, contentMode: .fill)
201+
}
102202
}
103203

104204
extension AnimatedImage {
@@ -123,4 +223,17 @@ extension AnimatedImage {
123223
}
124224
}
125225

226+
#if DEBUG
227+
struct AnimatedImage_Previews : PreviewProvider {
228+
static var previews: some View {
229+
Group {
230+
AnimatedImage(url: URL(string: "http://assets.sbnation.com/assets/2512203/dogflops.gif"))
231+
.resizable()
232+
.aspectRatio(contentMode: .fit)
233+
.padding()
234+
}
235+
}
236+
}
237+
#endif
238+
126239
#endif

SDWebImageSwiftUI/Classes/ImageManager.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ class ImageManager : ObservableObject {
1414

1515
var objectWillChange = PassthroughSubject<ImageManager, Never>()
1616

17-
private var manager = SDWebImageManager.shared
18-
private weak var currentOperation: SDWebImageOperation? = nil
17+
var manager = SDWebImageManager.shared
18+
weak var currentOperation: SDWebImageOperation? = nil
1919

20-
var image: Image? {
20+
var image: PlatformImage? {
2121
willSet {
2222
objectWillChange.send(self)
2323
}
@@ -36,11 +36,7 @@ class ImageManager : ObservableObject {
3636
func load() {
3737
currentOperation = manager.loadImage(with: url, options: options, context: context, progress: nil) { (image, data, error, cacheType, _, _) in
3838
if let image = image {
39-
#if os(macOS)
40-
self.image = Image(nsImage: image)
41-
#else
42-
self.image = Image(uiImage: image)
43-
#endif
39+
self.image = image
4440
}
4541
}
4642
}

0 commit comments

Comments
 (0)