开发需求的过程中,时常会碰到需要使用等网络图片加载完成后再进行渲染的场景,比如说:抽奖的大转盘,我们需要等奖品都加载渲染完成后再让用户进行抽奖。
1. 网络图片加载库
在Flutter中通常会使用cached_network_image下载网络图片,具体的集成和使用方法,请参考官方提供的 Install 和 Example 文档,这里不再进行赘述。
2. 使用ImageProvider下载图片
网络图片加载库cached_network_image 提供了CachedNetworkImageProvider
可以帮助将图片加载到内存中,详细代码如下:
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:cached_network_image/cached_network_image.dart';
Future loadImage(String url) async {
Completer completer = Completer();
ImageStreamListener? listener;
ImageStream stream =
CachedNetworkImageProvider(url).resolve(ImageConfiguration.empty);
listener = ImageStreamListener((ImageInfo frame, bool sync) {
final ui.Image image = frame.image;
completer.complete(image);
if (listener != null) {
stream.removeListener(listener);
}
});
stream.addListener(listener);
return completer.future;
}
这里需要这里的是:dart:ui.Image
,不能直接给 Image
Widget使用,还需要通过第三步将dart:ui.Image
转换成字节流。
3. 读取图片的字节流
dart:ui.Image
很贴心的为我们准备了 toByteData(format:)
方法,可以帮助我们很轻松的完成字节流转换,需要注意的是,因为用于 Image
Widget中进行展示,因此toByteData
方法的format
参数必须使用ImageByteFormat.png
, 详细代码如下:
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:cached_network_image/cached_network_image.dart';
Future downloadImageBytes() async {
var uiImage = await loadImage("https://i.pinimg.com/originals/85/03/93/85039311ce13e7cfd824e155a376003d.png");
var pngBytes = await uiImage.toByteData(format: ui.ImageByteFormat.png);
if (pngBytes != null) {
return pngBytes.buffer.asUint8List();
}
return null;
}
4. 使用Image Widget显示图片
接下来只需要使用Image.memory(imageBytesList)
加载内存中的图片数据即可。完整的示例如下:
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class ImageViewer extends StatefulWidget {
@override
State createState() {
return ImageViewerState();
}
}
class ImageViewerState extends State {
Uint8List? imageBytesList;
@override
void initState() {
super.initState();
downloadImageBytes().then((value) {
setState(() {
this.imageBytesList = value;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("显示加载的图片"),
),
body: Container(
height: double.infinity,
width: double.infinity,
child: imageBytesList != null ? Image.memory(imageBytesList!) : SizedBox.shrink(),
),
);
}
Future downloadImageBytes() async {
var uiImage = await loadImage("https://i.pinimg.com/originals/85/03/93/85039311ce13e7cfd824e155a376003d.png");
var pngBytes = await uiImage.toByteData(format: ui.ImageByteFormat.png);
if (pngBytes != null) {
return pngBytes.buffer.asUint8List();
}
return null;
}
Future loadImage(String url) async {
Completer completer = Completer();
ImageStreamListener? listener;
ImageStream stream =
CachedNetworkImageProvider(url).resolve(ImageConfiguration.empty);
listener = ImageStreamListener((ImageInfo frame, bool sync) {
final ui.Image image = frame.image;
completer.complete(image);
if (listener != null) {
stream.removeListener(listener);
}
});
stream.addListener(listener);
return completer.future;
}
}