import 'package:flutter/material.dart'; class MImage extends StatelessWidget { final String src; final String errorSrc; final String fadeSrc; final BorderRadius radius; final double aspectRatio; final double width; final double height; final BoxFit fit; MImage(this.src, { this.errorSrc, this.fadeSrc, this.aspectRatio, this.width, this.height, this.fit, this.radius = BorderRadius.zero, }); @override Widget build(BuildContext context) { var clipRRect = ClipRRect( borderRadius: radius, child: Image.network( src, fit: fit, errorBuilder: (context, error, stackTrace) { return Image.asset( errorSrc, fit: fit, ); }, frameBuilder: (context, child, frame, wasSynchronousLoaded) { if (wasSynchronousLoaded) { return child; } else { return AnimatedCrossFade( firstChild: child, layoutBuilder: (widgetFirst, keyFirst, widgetSecond, keySecond) { return Stack( clipBehavior: Clip.none, children: [ Positioned( key: keySecond, left: 0.0, top: 0.0, right: 0.0, bottom: 0.0, child: widgetSecond, ), Positioned( key: keyFirst, left: 0.0, top: 0.0, right: 0.0, bottom: 0.0, child: widgetFirst, ), ], ); }, secondChild: Image.asset( fadeSrc, fit: fit, ), crossFadeState: frame != null ? CrossFadeState.showFirst : CrossFadeState.showSecond, duration: Duration(milliseconds: 500), ); } }, excludeFromSemantics: true, ), ); if (aspectRatio != null && aspectRatio > 0) { return Container( child: AspectRatio( aspectRatio: aspectRatio, child: clipRRect, ), ); } else { return Container( width: width, height: height, child: clipRRect, ); } } }