Skip to content
This repository was archived by the owner on Apr 29, 2021. It is now read-only.

Commit 220ce21

Browse files
authored
Merge pull request #237 from luoxuuguang/master
add: add FadeInImage
2 parents fd0bd6d + d35e404 commit 220ce21

File tree

2 files changed

+375
-0
lines changed

2 files changed

+375
-0
lines changed

Runtime/widgets/fade_in_image.cs

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
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+
}

Runtime/widgets/fade_in_image.cs.meta

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

0 commit comments

Comments
 (0)