import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:hgdj/assets_tool/images.dart'; import 'package:hgdj/hj_utils/screen.dart'; import 'package:hgdj/tools_base/cache/image_cache_manager.dart'; class NetworkImageLoader extends StatelessWidget { final double borderRadius; final BorderRadius? imgBorderRadius; final String? imageUrl; final double? width; final double? height; final BoxFit fit; final double? placeHolderH; final double? placeHolderW; final bool blur; //高斯模糊 final Alignment alignment; final bool encrypt; //是否需要加密 final Widget? placeHolderWidget; final int? loadWidth; // 服务端根据宽度等比例压缩 final bool? isResizeImage; //是否需要根据组件大小压缩 const NetworkImageLoader({ super.key, required this.imageUrl, this.borderRadius = 8, this.imgBorderRadius, this.height, this.fit = BoxFit.cover, this.width, this.blur = false, this.placeHolderH, this.placeHolderW, this.alignment = Alignment.center, this.encrypt = true, this.placeHolderWidget, this.loadWidth, this.isResizeImage = true, }); bool get isGif => imageUrl?.contains(".gif") ?? false; String get realImgUrl { if (imageUrl == null) return ""; return imageUrl!; } @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, cons) { final imageWidget = CachedNetworkImage( alignment: alignment, imageUrl: realImgUrl, width: width, height: height, fit: fit, memCacheWidth: memCacheWidth(cons), // 默认 FilterQuality.low 用廉价 bilinear,iOS retina(dpr=3) 上肉眼可见的模糊 // medium 是质量/性能平衡点,high 会卡列表滚动 filterQuality: FilterQuality.medium, cacheManager: encrypt ? ImageCacheManager() : null, placeholder: (context, url) => _buildPlaceHolder(), errorWidget: (context, url, err) => _buildPlaceHolder(), fadeInCurve: Curves.linear, fadeOutCurve: Curves.linear, ); final clip = borderRadius == 0 ? imageWidget : ClipRRect( borderRadius: imgBorderRadius ?? BorderRadius.circular(borderRadius), child: imageWidget, ); final backdrop = blur ? ClipRRect( borderRadius: imgBorderRadius ?? BorderRadius.circular(borderRadius), child: ImageFiltered( imageFilter: ImageFilter.blur( sigmaX: 5, sigmaY: 5, ), child: clip, ), ) : clip; return backdrop; }); } //resize的宽度 int? memCacheWidth(BoxConstraints cons) { final dpr = screen.devicePixelRatio; if (isResizeImage == true) { //约束无限时用屏幕宽兜底,避免退化成按原图解码(图片过载) final w = (cons.maxWidth == double.infinity || cons.maxWidth.isNaN) ? screen.screenWidth : cons.maxWidth; return (w * dpr).toInt(); } else { return loadWidth != null ? loadWidth! : (screen.screenWidth * dpr).toInt(); } } _buildPlaceHolder() { if (placeHolderWidget != null) return placeHolderWidget; return Container( padding: EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration(color: Color(0xff343434)), alignment: Alignment.center, child: Image.asset( 'place_holder_logo.webp'.commonImgPath, width: placeHolderW ?? 136, height: placeHolderW ?? 96, ), ); } }