13_图片与资源
Flutter 图片加载和资源管理
静态资源管理、网络图片缓存、SVG 图片使用。
注册 assets 资源
所有静态资源必须在 pubspec.yaml 中声明才能使用:
flutter:
assets:
- assets/images/ # 整个目录(包含子目录需单独列出)
- assets/images/logo.png # 单个文件
- assets/data/cities.json
fonts:
- family: NotoSansSC
fonts:
- asset: assets/fonts/NotoSansSC-Regular.ttf
- asset: assets/fonts/NotoSansSC-Bold.ttf
weight: 700
使用本地 assets
// 本地图片
Image.asset(
'assets/images/banner.png',
width: double.infinity,
fit: BoxFit.cover,
)
// 读取 JSON 数据文件
import 'package:flutter/services.dart';
Future<List<dynamic>> loadCities() async {
final jsonString = await rootBundle.loadString('assets/data/cities.json');
return jsonDecode(jsonString) as List;
}
网络图片
Image.network(
'https://example.com/photo.jpg',
width: 200,
height: 150,
fit: BoxFit.cover,
loadingBuilder: (context, child, progress) {
if (progress == null) return child; // 已加载完成
return Center(
child: CircularProgressIndicator(
value: progress.cumulativeBytesLoaded / (progress.expectedTotalBytes ?? 1),
),
);
},
errorBuilder: (context, error, stackTrace) {
return const Icon(Icons.broken_image, size: 48, color: Colors.grey);
},
)
cached_network_image(带缓存的网络图片)
类似 next/image,自动缓存到磁盘,避免重复下载:
dependencies:
cached_network_image: ^3.3.0
import 'package:cached_network_image/cached_network_image.dart';
CachedNetworkImage(
imageUrl: 'https://example.com/photo.jpg',
width: 200,
height: 150,
fit: BoxFit.cover,
// 加载中占位
placeholder: (context, url) => Container(
color: Colors.grey.shade200,
child: const Center(child: CircularProgressIndicator()),
),
// 加载失败占位
errorWidget: (context, url, error) => Container(
color: Colors.grey.shade100,
child: const Icon(Icons.broken_image, color: Colors.grey),
),
// 内存缓存尺寸(按显示尺寸缓存,节省内存)
memCacheWidth: 200,
memCacheHeight: 150,
)
// 图片预加载(提前缓存下一页图片)
await precacheImage(
CachedNetworkImageProvider('https://example.com/next-image.jpg'),
context,
);
// 主动清除缓存
await CachedNetworkImage.evictFromCache('https://example.com/photo.jpg');
SVG 图片
dependencies:
flutter_svg: ^2.0.0
import 'package:flutter_svg/flutter_svg.dart';
// 本地 SVG
SvgPicture.asset(
'assets/icons/logo.svg',
width: 120,
height: 120,
colorFilter: const ColorFilter.mode(
Colors.blue,
BlendMode.srcIn, // 替换颜色(类似 CSS currentColor)
),
)
// 网络 SVG
SvgPicture.network(
'https://example.com/icon.svg',
width: 32,
height: 32,
placeholderBuilder: (_) => const SizedBox(
width: 32,
height: 32,
child: CircularProgressIndicator(strokeWidth: 2),
),
)
图片显示技巧
// 圆形图片(头像)
ClipOval(
child: CachedNetworkImage(
imageUrl: avatarUrl,
width: 80,
height: 80,
fit: BoxFit.cover,
),
)
// 圆角图片
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(imageUrl, fit: BoxFit.cover),
)
// 响应式图片(等比缩放)
AspectRatio(
aspectRatio: 16 / 9, // 类似 CSS aspect-ratio: 16/9
child: Image.network(imageUrl, fit: BoxFit.cover),
)
// 骨架屏(加载占位)
Container(
width: 200,
height: 150,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(8),
),
// 可配合 shimmer 包实现闪光效果
)
// BoxFit 速查
// BoxFit.cover → 裁剪填充(最常用,类似 object-fit: cover)
// BoxFit.contain → 保持比例,留白(类似 object-fit: contain)
// BoxFit.fill → 拉伸填充
// BoxFit.fitWidth → 宽度适配
// BoxFit.fitHeight→ 高度适配
// BoxFit.none → 原始尺寸,居中显示