Flutter实现图片完全加载完成后渲染

开发需求的过程中,时常会碰到需要使用等网络图片加载完成后再进行渲染的场景,比如说:抽奖的大转盘,我们需要等奖品都加载渲染完成后再让用户进行抽奖。

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;
  }
}

你可能感兴趣的:(Flutter实现图片完全加载完成后渲染)