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