flutter 如何展示从 dio http get 请求获取的图片?
5 个回答


回复之前先友情提醒,NetworkImage 是支持设置 headers,也就是可以设置 {" cookies":"xxxxxx" }
以下代码来自 NetworkImage ,因为 Flutter SDK 版本不同可能有一些偏差,正常拿到 response 数据后,如下代码所示,可以通过 consolidateHttpClientResponseBytes 方法将 bytes 获取到之后,通过 PaintingBinding. instance .instantiateImageCodec 转化为 ui.Codec
Future<ui.Codec> _loadAsync(
NetworkImage key,
StreamController<ImageChunkEvent> chunkEvents,
) async {
try {
assert(key == this);
final Uri resolved = Uri.base.resolve(key.url);
final HttpClientRequest request = await _httpClient.getUrl(resolved);
headers?.forEach((String name, String value) {
request.headers.add(name, value);
final HttpClientResponse response = await request.close();
if (response.statusCode != HttpStatus.ok)
throw image_provider.NetworkImageLoadException(statusCode: response.statusCode, uri: resolved);
final Uint8List bytes = await consolidateHttpClientResponseBytes(
response,
onBytesReceived: (int cumulative, int total) {
chunkEvents.add(ImageChunkEvent(
cumulativeBytesLoaded: cumulative,
expectedTotalBytes: total,
if (bytes.lengthInBytes == 0)
throw Exception('NetworkImage is an empty file: $resolved');
return PaintingBinding.instance.instantiateImageCodec(bytes);
} finally {
chunkEvents.close();
}
最后通过 MultiFrameImageStreamCompleter 中的 _handleAppFrame 提取出 _nextFrame.image
Future<void> _decodeNextFrameAndSchedule() async {
try {
_nextFrame = await _codec.getNextFrame();
} catch (exception, stack) {
reportError(
context: ErrorDescription('resolving an image frame'),
exception: exception,
stack: stack,
informationCollector: _informationCollector,
silent: true,
return;
if (_codec.frameCount == 1) {
// This is not an animated image, just return it and don't schedule more
// frames.
_emitFrame(ImageInfo(image: _nextFrame.image, scale: _scale));
return;
_scheduleAppFrame();
}
在 App 中会经常遇到需要从后台拉取图片的场景,这一方面会给服务器带来网络带宽消耗,另一方面加载图片的等待过程也会影响用户体验。因此,往往会在 App 端对图片做缓存机制,以避免同一张图片反复发起请求。在 Flutter 中,
cached_network_image
就提供了缓存网络图片功能,同时还提供了丰富的加载过程指示。同时 cached_network_image也提供了一个可选的httpHeaders 用于设置请求头,比如说鉴权 Cookies。
上一篇我们使用了列表,其中列表中有从网络下载图片。直接使用 Flutter 自带的
Image.network
下载图片一是无法缓存,二是体验不够好。熟悉 iOS 的肯定知道
SDWebImage
,即 Objective-C 上用得最广泛的图片缓存开源组件。与
SDWebImage
类似,Flutter 的 cached_network_image 插件也实现了这样的功能。cached_network_image 使用十分简单,首先在 pubspec.yaml 中添加依赖:
dependencies:
flutter:
sdk: flutter
# ...其他依赖
cached_network_image: ^3.0.0
之后在需要使用 cached_network_image 的地方引入源码:
import 'package:cached_network_image/cached_network_image.dart';
最后在需要加载网络图片的地方使用
cached_network_image
替代原有的图片加载方式(如 Image.network):
CachedNetworkImage(imageUrl: "http://via.placeholder.com/350x150"),
以上是
cached_network_image
最简单的用法,当然为了用户体验更好,推荐是使用占位图或
LoadingIndicator
的方式提示用户图片正在加载。
使用占位图
CachedNetworkImage
提供了占位图和加载失败后的错误指示的方法用于静态指示。我们分别准备 image-default.png 和 image-failed.png 文件表示默认占位图和加载失败后的占位图,然后用
CachedNetworkImage
构造方法的
placeholder
和
errorWidget
来使用占位图,如下所示:
Widget _imageWrapper(String imageUrl) {
return SizedBox(
width: 150,
height: ITEM_HEIGHT,
child: CachedNetworkImage(
imageUrl: imageUrl,
placeholder: (context, url) => Image.asset('images/image-default.png'),
errorWidget: (context, url, error) =>
Image.asset('images/image-failed.png'),
}
使用进度加载指示
也可以使用进度加载指示器来指示加载进度,加载进度指示支持原型进度和线型进度。这种对于大图预览时会更为常用,代码如下所示,其中
LinearProgressIndicator
是线型指示器,
CircularProgressIndicator
是圆形指示器:
Widget _imageWrapper(String imageUrl) {
return SizedBox(
width: 150,
height: ITEM_HEIGHT,
child: CachedNetworkImage(
imageUrl: imageUrl,
progressIndicatorBuilder: (context, url, downloadProgress) =>