95 lines
3.1 KiB
Dart
95 lines
3.1 KiB
Dart
import 'dart:ui';
|
||
|
||
import 'package:cached_network_image/cached_network_image.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:hjsq/assets_tool/images.dart';
|
||
import 'package:hjsq/hj_utils/screen.dart';
|
||
import 'package:hjsq/tools_base/cache/image_cache_manager.dart';
|
||
|
||
class NetworkImageLoader extends StatelessWidget {
|
||
final String? imageUrl;
|
||
final double? width;
|
||
final double? height;
|
||
final BoxFit fit;
|
||
final Alignment alignment;
|
||
|
||
final double borderRadius;
|
||
final BorderRadius? imgBorderRadius;
|
||
final bool blur; //高斯模糊
|
||
final bool encrypt; //是否需要加密
|
||
final Widget? placeHolderWidget;
|
||
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.alignment = Alignment.center,
|
||
this.encrypt = true,
|
||
this.placeHolderWidget,
|
||
this.isResizeImage = true,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return LayoutBuilder(builder: (context, cons) {
|
||
Widget image = CachedNetworkImage(
|
||
alignment: alignment,
|
||
imageUrl: imageUrl ?? '',
|
||
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) => _placeholder(),
|
||
errorWidget: (context, url, err) => _placeholder(),
|
||
fadeInCurve: Curves.linear,
|
||
fadeOutCurve: Curves.linear,
|
||
);
|
||
final radius = imgBorderRadius ?? BorderRadius.circular(borderRadius);
|
||
if (borderRadius != 0)
|
||
image = ClipRRect(borderRadius: radius, child: image);
|
||
//模糊会溢出边界,外面再裁一层
|
||
if (blur) {
|
||
image = ClipRRect(
|
||
borderRadius: radius,
|
||
child: ImageFiltered(
|
||
imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||
child: image),
|
||
);
|
||
}
|
||
return image;
|
||
});
|
||
}
|
||
|
||
//resize的宽度
|
||
int _memCacheWidth(BoxConstraints cons) {
|
||
final dpr = screen.devicePixelRatio;
|
||
if (!isResizeImage) return (screen.screenWidth * dpr).toInt();
|
||
//约束无限时用屏幕宽兜底,避免退化成按原图解码(图片过载)
|
||
final w = (cons.maxWidth == double.infinity || cons.maxWidth.isNaN)
|
||
? screen.screenWidth
|
||
: cons.maxWidth;
|
||
return (w * dpr).toInt();
|
||
}
|
||
|
||
Widget _placeholder() {
|
||
if (placeHolderWidget != null) return placeHolderWidget!;
|
||
return Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||
decoration: const BoxDecoration(color: Color(0xff151E2D)),
|
||
alignment: Alignment.center,
|
||
child: Image.asset('place_holder_logo.webp'.commonImgPath,
|
||
width: 100, height: 35),
|
||
);
|
||
}
|
||
}
|