1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/material.dart'; |
6 | |
7 | /// An image that shows a [placeholder] widget while the target [image] is |
8 | /// loading, then fades in the new image when it loads. |
9 | /// |
10 | /// This is similar to [FadeInImage] but the difference is that it allows you |
11 | /// to specify a widget as a [placeholder], instead of just an [ImageProvider]. |
12 | /// It also lets you override the [child] argument, in case you want to wrap |
13 | /// the image with another widget, for example an [Ink.image]. |
14 | class FadeInImagePlaceholder extends StatelessWidget { |
15 | const FadeInImagePlaceholder({ |
16 | super.key, |
17 | required this.image, |
18 | required this.placeholder, |
19 | this.child, |
20 | this.duration = const Duration(milliseconds: 500), |
21 | this.excludeFromSemantics = false, |
22 | this.width, |
23 | this.height, |
24 | this.fit, |
25 | }); |
26 | |
27 | /// The target image that we are loading into memory. |
28 | final ImageProvider image; |
29 | |
30 | /// Widget displayed while the target [image] is loading. |
31 | final Widget placeholder; |
32 | |
33 | /// What widget you want to display instead of [placeholder] after [image] is |
34 | /// loaded. |
35 | /// |
36 | /// Defaults to display the [image]. |
37 | final Widget? child; |
38 | |
39 | /// The duration for how long the fade out of the placeholder and |
40 | /// fade in of [child] should take. |
41 | final Duration duration; |
42 | |
43 | /// See [Image.excludeFromSemantics]. |
44 | final bool excludeFromSemantics; |
45 | |
46 | /// See [Image.width]. |
47 | final double? width; |
48 | |
49 | /// See [Image.height]. |
50 | final double? height; |
51 | |
52 | /// See [Image.fit]. |
53 | final BoxFit? fit; |
54 | |
55 | @override |
56 | Widget build(BuildContext context) { |
57 | return Image( |
58 | image: image, |
59 | excludeFromSemantics: excludeFromSemantics, |
60 | width: width, |
61 | height: height, |
62 | fit: fit, |
63 | frameBuilder: (BuildContext context, Widget child, int? frame, bool wasSynchronouslyLoaded) { |
64 | if (wasSynchronouslyLoaded) { |
65 | return this.child ?? child; |
66 | } else { |
67 | return AnimatedSwitcher( |
68 | duration: duration, |
69 | child: frame != null ? this.child ?? child : placeholder, |
70 | ); |
71 | } |
72 | }, |
73 | ); |
74 | } |
75 | } |
76 | |