1
+ using System ;
2
+ using Unity . UIWidgets . animation ;
3
+ using Unity . UIWidgets . foundation ;
4
+ using Unity . UIWidgets . painting ;
5
+ using Unity . UIWidgets . ui ;
6
+ using UnityEngine ;
7
+ using Color = Unity . UIWidgets . ui . Color ;
8
+
9
+ namespace Unity . UIWidgets . widgets {
10
+ public class FadeInImage : StatefulWidget {
11
+ public FadeInImage (
12
+ ImageProvider placeholder ,
13
+ ImageProvider image ,
14
+ TimeSpan ? fadeOutDuration = null ,
15
+ Curve fadeOutCurve = null ,
16
+ TimeSpan ? fadeInDuration = null ,
17
+ Curve fadeInCurve = null ,
18
+ float ? width = null ,
19
+ float ? height = null ,
20
+ BoxFit ? fit = null ,
21
+ Alignment alignment = null ,
22
+ ImageRepeat repeat = ImageRepeat . noRepeat ,
23
+ Key key = null
24
+ ) : base ( key ) {
25
+ D . assert ( placeholder != null ) ;
26
+ D . assert ( image != null ) ;
27
+ D . assert ( fadeOutDuration != null ) ;
28
+ D . assert ( fadeOutCurve != null ) ;
29
+ D . assert ( fadeInDuration != null ) ;
30
+ D . assert ( fadeInCurve != null ) ;
31
+ D . assert ( alignment != null ) ;
32
+ this . placeholder = placeholder ;
33
+ this . image = image ;
34
+ this . width = width ;
35
+ this . height = height ;
36
+ this . fit = fit ;
37
+ this . fadeOutDuration = fadeOutDuration ?? TimeSpan . FromMilliseconds ( 300 ) ;
38
+ this . fadeOutCurve = fadeOutCurve ?? Curves . easeOut ;
39
+ this . fadeInDuration = fadeInDuration ?? TimeSpan . FromMilliseconds ( 700 ) ;
40
+ this . fadeInCurve = fadeInCurve ?? Curves . easeIn ;
41
+ this . alignment = alignment ?? Alignment . center ;
42
+ this . repeat = repeat ;
43
+ }
44
+
45
+ public static FadeInImage memoryNetwork (
46
+ byte [ ] placeholder ,
47
+ string image ,
48
+ float placeholderScale = 1.0f ,
49
+ float imageScale = 1.0f ,
50
+ TimeSpan ? fadeOutDuration = null ,
51
+ Curve fadeOutCurve = null ,
52
+ TimeSpan ? fadeInDuration = null ,
53
+ Curve fadeInCurve = null ,
54
+ float ? width = null ,
55
+ float ? height = null ,
56
+ BoxFit ? fit = null ,
57
+ Alignment alignment = null ,
58
+ ImageRepeat repeat = ImageRepeat . noRepeat ,
59
+ Key key = null
60
+ ) {
61
+ D . assert ( placeholder != null ) ;
62
+ D . assert ( image != null ) ;
63
+ D . assert ( fadeOutDuration != null ) ;
64
+ D . assert ( fadeOutCurve != null ) ;
65
+ D . assert ( fadeInDuration != null ) ;
66
+ D . assert ( fadeInCurve != null ) ;
67
+ D . assert ( alignment != null ) ;
68
+ var memoryImage = new MemoryImage ( placeholder , placeholderScale ) ;
69
+ var networkImage = new NetworkImage ( image , imageScale ) ;
70
+ return new FadeInImage (
71
+ memoryImage ,
72
+ networkImage ,
73
+ fadeOutDuration ,
74
+ fadeOutCurve ,
75
+ fadeInDuration ,
76
+ fadeInCurve ,
77
+ width , height ,
78
+ fit ,
79
+ alignment ,
80
+ repeat ,
81
+ key
82
+ ) ;
83
+ }
84
+
85
+ public static FadeInImage assetNetwork (
86
+ string placeholder ,
87
+ string image ,
88
+ AssetBundle bundle = null ,
89
+ float ? placeholderScale = null ,
90
+ float imageScale = 1.0f ,
91
+ TimeSpan ? fadeOutDuration = null ,
92
+ Curve fadeOutCurve = null ,
93
+ TimeSpan ? fadeInDuration = null ,
94
+ Curve fadeInCurve = null ,
95
+ float ? width = null ,
96
+ float ? height = null ,
97
+ BoxFit ? fit = null ,
98
+ Alignment alignment = null ,
99
+ ImageRepeat repeat = ImageRepeat . noRepeat ,
100
+ Key key = null
101
+ ) {
102
+ D . assert ( placeholder != null ) ;
103
+ D . assert ( image != null ) ;
104
+ D . assert ( fadeOutDuration != null ) ;
105
+ D . assert ( fadeOutCurve != null ) ;
106
+ D . assert ( fadeInDuration != null ) ;
107
+ D . assert ( fadeInCurve != null ) ;
108
+ D . assert ( alignment != null ) ;
109
+ var imageProvider = placeholderScale != null
110
+ ? new ExactAssetImage ( placeholder , bundle : bundle , scale : placeholderScale ?? 1.0f )
111
+ : ( ImageProvider ) new AssetImage ( placeholder , bundle : bundle ) ;
112
+
113
+ var networkImage = new NetworkImage ( image , imageScale ) ;
114
+ return new FadeInImage (
115
+ imageProvider ,
116
+ networkImage ,
117
+ fadeOutDuration ,
118
+ fadeOutCurve ,
119
+ fadeInDuration ,
120
+ fadeInCurve ,
121
+ width , height ,
122
+ fit ,
123
+ alignment ,
124
+ repeat ,
125
+ key
126
+ ) ;
127
+ }
128
+
129
+ public readonly ImageProvider placeholder ;
130
+ public readonly ImageProvider image ;
131
+ public readonly TimeSpan fadeOutDuration ;
132
+ public readonly Curve fadeOutCurve ;
133
+ public readonly TimeSpan fadeInDuration ;
134
+ public readonly Curve fadeInCurve ;
135
+ public readonly float ? width ;
136
+ public readonly float ? height ;
137
+ public readonly BoxFit ? fit ;
138
+ public readonly Alignment alignment ;
139
+ public readonly ImageRepeat repeat ;
140
+
141
+ public override State createState ( ) {
142
+ return new _FadeInImageState ( ) ;
143
+ }
144
+ }
145
+
146
+ enum FadeInImagePhase {
147
+ start ,
148
+ waiting ,
149
+ fadeOut ,
150
+ fadeIn ,
151
+ completed
152
+ }
153
+
154
+ delegate void _ImageProviderResolverListener ( ) ;
155
+
156
+ class _ImageProviderResolver {
157
+ public _ImageProviderResolver (
158
+ _FadeInImageState state ,
159
+ _ImageProviderResolverListener listener
160
+ ) {
161
+ this . state = state ;
162
+ this . listener = listener ;
163
+ }
164
+
165
+ readonly _FadeInImageState state ;
166
+ readonly _ImageProviderResolverListener listener ;
167
+
168
+ FadeInImage widget {
169
+ get { return this . state . widget ; }
170
+ }
171
+
172
+ public ImageStream _imageStream ;
173
+ public ImageInfo _imageInfo ;
174
+
175
+ public void resolve ( ImageProvider provider ) {
176
+ ImageStream oldImageStream = this . _imageStream ;
177
+ Size size = null ;
178
+ if ( this . widget . width != null && this . widget . height != null ) {
179
+ size = new Size ( ( int ) this . widget . width , ( int ) this . widget . height ) ;
180
+ }
181
+
182
+ this . _imageStream = provider . resolve ( ImageUtils . createLocalImageConfiguration ( this . state . context , size ) ) ;
183
+ D . assert ( this . _imageStream != null ) ;
184
+
185
+ if ( this . _imageStream . key != oldImageStream ? . key ) {
186
+ oldImageStream ? . removeListener ( this . _handleImageChanged ) ;
187
+ this . _imageStream . addListener ( this . _handleImageChanged ) ;
188
+ }
189
+ }
190
+
191
+ void _handleImageChanged ( ImageInfo imageInfo , bool synchronousCall ) {
192
+ this . _imageInfo = imageInfo ;
193
+ this . listener ( ) ;
194
+ }
195
+
196
+ public void stopListening ( ) {
197
+ this . _imageStream ? . removeListener ( this . _handleImageChanged ) ;
198
+ }
199
+ }
200
+
201
+
202
+ class _FadeInImageState : TickerProviderStateMixin < FadeInImage > {
203
+ _ImageProviderResolver _imageResolver ;
204
+ _ImageProviderResolver _placeholderResolver ;
205
+
206
+ AnimationController _controller ;
207
+ Animation < float > _animation ;
208
+
209
+ FadeInImagePhase _phase = FadeInImagePhase . start ;
210
+
211
+ public override void initState ( ) {
212
+ this . _imageResolver = new _ImageProviderResolver ( state : this , this . _updatePhase ) ;
213
+ this . _placeholderResolver = new _ImageProviderResolver ( state : this , listener : ( ) => {
214
+ this . setState ( ( ) => {
215
+ // Trigger rebuild to display the placeholder image
216
+ } ) ;
217
+ } ) ;
218
+ this . _controller = new AnimationController (
219
+ value : 1.0f ,
220
+ vsync : this
221
+ ) ;
222
+ this . _controller . addListener ( ( ) => {
223
+ this . setState ( ( ) => {
224
+ // Trigger rebuild to update opacity value.
225
+ } ) ;
226
+ } ) ;
227
+ this . _controller . addStatusListener ( status => { this . _updatePhase ( ) ; } ) ;
228
+ base . initState ( ) ;
229
+ }
230
+
231
+ public override void didChangeDependencies ( ) {
232
+ this . _resolveImage ( ) ;
233
+ base . didChangeDependencies ( ) ;
234
+ }
235
+
236
+ public override void didUpdateWidget ( StatefulWidget oldWidget ) {
237
+ base . didUpdateWidget ( oldWidget ) ;
238
+ FadeInImage fadeInImage = oldWidget as FadeInImage ;
239
+ if ( this . widget . image != fadeInImage . image || this . widget . placeholder != fadeInImage . placeholder ) {
240
+ this . _resolveImage ( ) ;
241
+ }
242
+ }
243
+
244
+ void _resolveImage ( ) {
245
+ this . _imageResolver . resolve ( this . widget . image ) ;
246
+
247
+ if ( this . _isShowingPlaceholder ) {
248
+ this . _placeholderResolver . resolve ( this . widget . placeholder ) ;
249
+ }
250
+
251
+ if ( this . _phase == FadeInImagePhase . start ) {
252
+ this . _updatePhase ( ) ;
253
+ }
254
+ }
255
+
256
+ void _updatePhase ( ) {
257
+ this . setState ( ( ) => {
258
+ switch ( this . _phase ) {
259
+ case FadeInImagePhase . start :
260
+ if ( this . _imageResolver . _imageInfo != null ) {
261
+ this . _phase = FadeInImagePhase . completed ;
262
+ }
263
+ else {
264
+ this . _phase = FadeInImagePhase . waiting ;
265
+ }
266
+
267
+ break ;
268
+ case FadeInImagePhase . waiting :
269
+ if ( this . _imageResolver . _imageInfo != null ) {
270
+ this . _controller . duration = this . widget . fadeOutDuration ;
271
+ this . _animation = new CurvedAnimation (
272
+ parent : this . _controller ,
273
+ curve : this . widget . fadeOutCurve
274
+ ) ;
275
+ this . _phase = FadeInImagePhase . fadeOut ;
276
+ this . _controller . reverse ( 1.0f ) ;
277
+ }
278
+
279
+ break ;
280
+ case FadeInImagePhase . fadeOut :
281
+ if ( this . _controller . status == AnimationStatus . dismissed ) {
282
+ // Done fading out placeholder. Begin target image fade-in.
283
+ this . _controller . duration = this . widget . fadeInDuration ;
284
+ this . _animation = new CurvedAnimation (
285
+ parent : this . _controller ,
286
+ curve : this . widget . fadeInCurve
287
+ ) ;
288
+ this . _phase = FadeInImagePhase . fadeIn ;
289
+ this . _placeholderResolver . stopListening ( ) ;
290
+ this . _controller . forward ( 0.0f ) ;
291
+ }
292
+
293
+ break ;
294
+ case FadeInImagePhase . fadeIn :
295
+ if ( this . _controller . status == AnimationStatus . completed ) {
296
+ // Done finding in new image.
297
+ this . _phase = FadeInImagePhase . completed ;
298
+ }
299
+
300
+ break ;
301
+ case FadeInImagePhase . completed :
302
+ // Nothing to do.
303
+ break ;
304
+ }
305
+ } ) ;
306
+ }
307
+
308
+ public override void dispose ( ) {
309
+ this . _imageResolver . stopListening ( ) ;
310
+ this . _placeholderResolver . stopListening ( ) ;
311
+ this . _controller . dispose ( ) ;
312
+ base . dispose ( ) ;
313
+ }
314
+
315
+ bool _isShowingPlaceholder {
316
+ get {
317
+ switch ( this . _phase ) {
318
+ case FadeInImagePhase . start :
319
+ case FadeInImagePhase . waiting :
320
+ case FadeInImagePhase . fadeOut :
321
+ return true ;
322
+ case FadeInImagePhase . fadeIn :
323
+ case FadeInImagePhase . completed :
324
+ return false ;
325
+ }
326
+
327
+ return true ;
328
+ }
329
+ }
330
+
331
+ ImageInfo _imageInfo {
332
+ get {
333
+ return this . _isShowingPlaceholder
334
+ ? this . _placeholderResolver . _imageInfo
335
+ : this . _imageResolver . _imageInfo ;
336
+ }
337
+ }
338
+
339
+ public override Widget build ( BuildContext context ) {
340
+ D . assert ( this . _phase != FadeInImagePhase . start ) ;
341
+ ImageInfo imageInfo = this . _imageInfo ;
342
+ return new RawImage (
343
+ image : imageInfo ? . image ,
344
+ width : this . widget . width ,
345
+ height : this . widget . height ,
346
+ scale : imageInfo ? . scale ?? 1.0f ,
347
+ color : Color . fromRGBO ( 255 , 255 , 255 , this . _animation ? . value ?? 1.0f ) ,
348
+ colorBlendMode : BlendMode . modulate ,
349
+ fit : this . widget . fit ,
350
+ alignment : this . widget . alignment ,
351
+ repeat : this . widget . repeat
352
+ ) ;
353
+ }
354
+
355
+ public override void debugFillProperties ( DiagnosticPropertiesBuilder properties ) {
356
+ base . debugFillProperties ( properties ) ;
357
+ properties . add ( new EnumProperty < FadeInImagePhase > ( "phase" , this . _phase ) ) ;
358
+ properties . add ( new DiagnosticsProperty < ImageInfo > ( "pixels" , this . _imageInfo ) ) ;
359
+ properties . add ( new DiagnosticsProperty < ImageStream > ( "image stream" , this . _imageResolver . _imageStream ) ) ;
360
+ properties . add ( new DiagnosticsProperty < ImageStream > ( "placeholder stream" ,
361
+ this . _placeholderResolver . _imageStream ) ) ;
362
+ }
363
+ }
364
+ }
0 commit comments