Reputation: 3
I have a list of speakers. When I click on any of the items, I navigate to a page with details about that speaker. During the transition, a small avatar transforms into a large one using the Hero
widget. These avatars are CachedNetworkImages
. In the normal state (when the image is successfully loaded from the network), everything works fine. However, if you simulate a situation where the image does not load, or another error occurs, the errorWidget
of the CachedNetworkImages
begins to flicker during the transition.
GIF of how it looks now: https://imgur.com/a/E7ogQhV
(Sorry, For some unknown reason, I can't load this through the site.)
I tried fetching the image myself and, depending on the response code, choosing to display either the placeholder widget or the CachedNetworkImages
. However, a different behavior arose, where the placeholder widget was displayed at the beginning even if the image had already been successfully loaded.
class NetworkImageWidget extends StatefulWidget {
const NetworkImageWidget({
super.key,
required this.imageUrl,
this.width,
this.height,
this.fit = BoxFit.cover,
});
final String? imageUrl;
final double? width;
final double? height;
final BoxFit? fit;
@override
State<NetworkImageWidget> createState() => _NetworkImageWidgetState();
}
class _NetworkImageWidgetState extends State<NetworkImageWidget> {
@override
void initState() {
super.initState();
// fetchImage();
}
bool isImageReal = false;
bool get _isImageInvalid =>
(widget.imageUrl?.isEmpty ?? true) ||
(!widget.imageUrl!.startsWith('http') || !isImageReal);
// Future<void> fetchImage() async {
//
// final response = await http.get(Uri.parse(widget.imageUrl!));
// if (response.statusCode == 200) {
// setState(() => isImageReal = true);
// } else {
// setState(() => isImageReal = false);
// }
// }
@override
Widget build(BuildContext context) {
// if (_isImageInvalid) {
// return _PlaceHolderImageWidget(
// width: widget.width,
// height: widget.height,
// fit: widget.fit,
// );
// }
return CachedNetworkImage(
imageUrl: widget.imageUrl!,
width: widget.width,
height: widget.height,
fit: widget.fit,
// cacheManager: CacheManager,
placeholder: (_, __) => _CircleImageShimmer(
width: widget.width,
height: widget.height,
),
errorWidget: (_, __, ___) => _PlaceHolderImageWidget(
width: widget.width,
height: widget.height,
fit: widget.fit,
),
);
}
}
class _CircleImageShimmer extends StatelessWidget {
const _CircleImageShimmer({
required this.width,
required this.height,
});
final double? width;
final double? height;
@override
Widget build(BuildContext context) {
final appColor = AppColorScheme.of(context);
return Shimmer.fromColors(
baseColor: appColor.shimmer,
highlightColor: appColor.shimmerHighlight,
child: Container(
color: Colors.white,
width: width,
height: height,
),
);
}
}
class _PlaceHolderImageWidget extends StatelessWidget {
const _PlaceHolderImageWidget({this.width, this.height, this.fit});
final double? width;
final double? height;
final BoxFit? fit;
@override
Widget build(BuildContext context) => Image.asset(
Images.largePlaceholder,
width: width,
height: height,
fit: fit,
);
}
This is my widget code for the CachedNetworkImages
, which I then wrap in a Hero
widget.
Upvotes: 0
Views: 69