// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; /// An image that shows a [placeholder] widget while the target [image] is /// loading, then fades in the new image when it loads. /// /// This is similar to [FadeInImage] but the difference is that it allows you /// to specify a widget as a [placeholder], instead of just an [ImageProvider]. /// It also lets you override the [child] argument, in case you want to wrap /// the image with another widget, for example an [Ink.image]. class FadeInImagePlaceholder extends StatelessWidget { const FadeInImagePlaceholder({ super.key, required this.image, required this.placeholder, this.child, this.duration = const Duration(milliseconds: 500), this.excludeFromSemantics = false, this.width, this.height, this.fit, }); /// The target image that we are loading into memory. final ImageProvider image; /// Widget displayed while the target [image] is loading. final Widget placeholder; /// What widget you want to display instead of [placeholder] after [image] is /// loaded. /// /// Defaults to display the [image]. final Widget? child; /// The duration for how long the fade out of the placeholder and /// fade in of [child] should take. final Duration duration; /// See [Image.excludeFromSemantics]. final bool excludeFromSemantics; /// See [Image.width]. final double? width; /// See [Image.height]. final double? height; /// See [Image.fit]. final BoxFit? fit; @override Widget build(BuildContext context) { return Image( image: image, excludeFromSemantics: excludeFromSemantics, width: width, height: height, fit: fit, frameBuilder: (BuildContext context, Widget child, int? frame, bool wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded) { return this.child ?? child; } else { return AnimatedSwitcher( duration: duration, child: frame != null ? this.child ?? child : placeholder, ); } }, ); } }