图片加载是性能与体验高频问题。与其每个页面重复处理,不如封装一个统一组件,保证占位/错误/缓存策略一致。
0. 依赖
dependencies:
cached_network_image: ^3.3.1
1. 统一图片组件
class AppImage extends StatelessWidget {
final String? url;
final double? width;
final double? height;
final BoxFit fit;
final String placeholder;
final String error;
const AppImage({
super.key,
this.url,
this.width,
this.height,
this.fit = BoxFit.cover,
this.placeholder = 'assets/images/placeholder.png',
this.error = 'assets/images/error.png',
});
@override
Widget build(BuildContext context) {
if (url == null || url!.isEmpty) {
return Image.asset(placeholder, width: width, height: height, fit: fit);
}
return CachedNetworkImage(
imageUrl: url!,
width: width,
height: height,
fit: fit,
placeholder: (_, __) => Image.asset(placeholder, fit: fit),
errorWidget: (_, __, ___) => Image.asset(error, fit: fit),
);
}
}
2. 使用方式
AppImage(url: user.avatar, width: 48, height: 48, fit: BoxFit.cover);
3. 缓存策略
final customCache = CacheManager(
Config('images', stalePeriod: const Duration(days: 7))
);
CachedNetworkImage(
imageUrl: url,
cacheManager: customCache,
);
4. 常用扩展
4.1 圆角头像
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: AppImage(url: user.avatar, width: 48, height: 48),
)
4.2 渐进加载
CachedNetworkImage(
imageUrl: url,
placeholder: (_, __) => const CircularProgressIndicator(),
)
4.3 失败兜底
CachedNetworkImage(
imageUrl: url,
errorWidget: (_, __, ___) => Image.asset('assets/images/error.png'),
)
5. 常见坑点
- URL 为空:务必用占位图兜底
- 大图内存:尽量传缩略图或控制尺寸
- 缓存策略不一致:统一 CacheManager
6. 实践清单
- 统一封装图片组件
- 统一占位 / 错误图
- 缓存策略可控