@@ -20,6 +20,23 @@ extension View {
20
20
}
21
21
}
22
22
23
+ extension AnimatedImage {
24
+ struct WrapperView : View & Inspectable {
25
+ var name : String
26
+ var bundle : Bundle ?
27
+ @State var isAnimating : Bool
28
+
29
+ var onViewUpdate : ( Self , PlatformView , AnimatedImage . Context ) -> Void
30
+
31
+ var body : some View {
32
+ AnimatedImage ( name: name, bundle: bundle, isAnimating: $isAnimating)
33
+ . onViewUpdate { view, context in
34
+ self . onViewUpdate ( self , view, context)
35
+ }
36
+ }
37
+ }
38
+ }
39
+
23
40
class AnimatedImageTests : XCTestCase {
24
41
25
42
override func setUp( ) {
@@ -89,38 +106,50 @@ class AnimatedImageTests: XCTestCase {
89
106
90
107
func testAnimatedImageBinding( ) throws {
91
108
let expectation = self . expectation ( description: " AnimatedImage binding control " )
92
- let binding = Binding < Bool > ( wrappedValue: true )
93
- var context : AnimatedImage . Context ?
94
- let imageView = AnimatedImage ( name: " TestLoopCount.gif " , bundle: TestUtils . testImageBundle ( ) , isAnimating: binding)
95
- . onViewCreate { _, c in
96
- context = c
97
- }
98
- let introspectView = imageView. introspectAnimatedImage { animatedImageView in
109
+ var viewUpdateCount = 0
110
+ // Use wrapper to make the @Binding works
111
+ let wrapperView = AnimatedImage . WrapperView ( name: " TestLoopCount.gif " , bundle: TestUtils . testImageBundle ( ) , isAnimating: true ) { wrapperView, view, context in
112
+ viewUpdateCount += 1
113
+ guard let animatedImageView = view as? SDAnimatedImageView else {
114
+ XCTFail ( " AnimatedImage's view should be SDAnimatedImageView " )
115
+ return
116
+ }
99
117
if let animatedImage = animatedImageView. image as? SDAnimatedImage {
100
118
XCTAssertEqual ( animatedImage. animatedImageLoopCount, 1 )
101
119
XCTAssertEqual ( animatedImage. animatedImageFrameCount, 2 )
102
120
} else {
103
- XCTFail ( " SDAnimatedImageView. image invalid " )
121
+ XCTFail ( " AnimatedImage's image should be SDAnimatedImage " )
104
122
}
105
- #if os(iOS) || os(tvOS)
106
- XCTAssertTrue ( animatedImageView. isAnimating)
123
+ // View update times before stable from SwiftUI, different behavior for AppKit/UIKit
124
+ #if os(macOS)
125
+ let stableViewUpdateCount = 1
107
126
#else
108
- XCTAssertTrue ( animatedImageView . animates )
127
+ let stableViewUpdateCount = 2
109
128
#endif
110
- binding. wrappedValue = false
111
- XCTAssertFalse ( binding. wrappedValue)
112
- XCTAssertFalse ( imageView. isAnimating)
113
- // Currently ViewInspector's @Binding value update does not trigger `UIViewRepresentable.updateUIView`, mock here
114
- imageView. updateView ( animatedImageView. superview as! AnimatedImageViewWrapper , context: context!)
115
- #if os(iOS) || os(tvOS)
116
- XCTAssertFalse ( animatedImageView. isAnimating)
117
- #else
118
- XCTAssertFalse ( animatedImageView. animates)
119
- #endif
120
- expectation. fulfill ( )
129
+ switch viewUpdateCount {
130
+ case stableViewUpdateCount:
131
+ // #1 SwiftUI's own updateUIView call
132
+ #if os(iOS) || os(tvOS)
133
+ XCTAssertTrue ( animatedImageView. isAnimating)
134
+ #else
135
+ XCTAssertTrue ( animatedImageView. animates)
136
+ #endif
137
+ DispatchQueue . main. async {
138
+ wrapperView. isAnimating = false
139
+ }
140
+ case stableViewUpdateCount + 1 :
141
+ // #3 AnimatedImage's isAnimating @Binding trigger update (from above)
142
+ #if os(iOS) || os(tvOS)
143
+ XCTAssertFalse ( animatedImageView. isAnimating)
144
+ #else
145
+ XCTAssertFalse ( animatedImageView. animates)
146
+ #endif
147
+ expectation. fulfill ( )
148
+ default : break
149
+ // do not care
150
+ }
121
151
}
122
- _ = try introspectView. inspect ( AnimatedImage . self)
123
- ViewHosting . host ( view: introspectView)
152
+ ViewHosting . host ( view: wrapperView)
124
153
self . waitForExpectations ( timeout: 5 , handler: nil )
125
154
}
126
155
0 commit comments