@@ -20,6 +20,10 @@ final class AnimatedImageModel : ObservableObject {
20
20
// Layout Binding Object
21
21
final class AnimatedImageLayout : ObservableObject {
22
22
@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
23
27
}
24
28
25
29
// View
@@ -31,53 +35,115 @@ public struct AnimatedImage : ViewRepresentable {
31
35
var webContext : [ SDWebImageContextOption : Any ] ? = nil
32
36
33
37
#if os(macOS)
34
- public typealias NSViewType = SDAnimatedImageView
38
+ public typealias NSViewType = AnimatedImageViewWrapper
35
39
#else
36
- public typealias UIViewType = SDAnimatedImageView
40
+ public typealias UIViewType = AnimatedImageViewWrapper
37
41
#endif
38
42
39
43
#if os(macOS)
40
- public func makeNSView( context: NSViewRepresentableContext < AnimatedImage > ) -> SDAnimatedImageView {
44
+ public func makeNSView( context: NSViewRepresentableContext < AnimatedImage > ) -> AnimatedImageViewWrapper {
41
45
makeView ( context: context)
42
46
}
43
47
44
- public func updateNSView( _ nsView: SDAnimatedImageView , context: NSViewRepresentableContext < AnimatedImage > ) {
48
+ public func updateNSView( _ nsView: AnimatedImageViewWrapper , context: NSViewRepresentableContext < AnimatedImage > ) {
45
49
updateView ( nsView, context: context)
46
50
}
47
51
#else
48
- public func makeUIView( context: UIViewRepresentableContext < AnimatedImage > ) -> SDAnimatedImageView {
52
+ public func makeUIView( context: UIViewRepresentableContext < AnimatedImage > ) -> AnimatedImageViewWrapper {
49
53
makeView ( context: context)
50
54
}
51
55
52
- public func updateUIView( _ uiView: SDAnimatedImageView , context: UIViewRepresentableContext < AnimatedImage > ) {
56
+ public func updateUIView( _ uiView: AnimatedImageViewWrapper , context: UIViewRepresentableContext < AnimatedImage > ) {
53
57
updateView ( uiView, context: context)
54
58
}
55
59
#endif
56
60
57
- func makeView( context: ViewRepresentableContext < AnimatedImage > ) -> SDAnimatedImageView {
58
- SDAnimatedImageView ( )
61
+ func makeView( context: ViewRepresentableContext < AnimatedImage > ) -> AnimatedImageViewWrapper {
62
+ AnimatedImageViewWrapper ( )
59
63
}
60
64
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
63
67
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)
65
69
}
66
70
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
67
81
switch imageLayout. contentMode {
68
82
case . fit:
69
83
#if os(macOS)
70
- view. imageScaling = . scaleProportionallyUpOrDown
84
+ view. wrapped . imageScaling = . scaleProportionallyUpOrDown
71
85
#else
72
- view. contentMode = . scaleAspectFit
86
+ view. wrapped . contentMode = . scaleAspectFit
73
87
#endif
74
88
case . fill:
75
89
#if os(macOS)
76
- view. imageScaling = . scaleAxesIndependently
90
+ view. wrapped . imageScaling = . scaleAxesIndependently
77
91
#else
78
- view. contentMode = . scaleToFill
92
+ view. wrapped . contentMode = . scaleToFill
79
93
#endif
80
94
}
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
81
147
}
82
148
83
149
public func image( _ image: SDAnimatedImage ? ) -> Self {
@@ -90,15 +156,49 @@ public struct AnimatedImage : ViewRepresentable {
90
156
return self
91
157
}
92
158
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
95
178
return self
96
179
}
97
180
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
100
184
return self
101
185
}
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
+ }
102
202
}
103
203
104
204
extension AnimatedImage {
@@ -123,4 +223,17 @@ extension AnimatedImage {
123
223
}
124
224
}
125
225
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
+
126
239
#endif
0 commit comments