Flutter CustomPainter绘制图片不起作用

8

我尝试使用Canvas和CustomPainter绘制图像,但却没有成功。这是在Flutter Framework下开发Android应用所遇到的问题。

我只是在Windows命令行中使用flutter build apk命令构建了该应用。

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(title: Text('Title!')),
      body: Center(
        child: AspectRatio(
          aspectRatio: 1.0,
          child: CustomPaint(
            painter: ImageEditor(),
          ),
        ),
      ),
    );
  }
}

class ImageEditor extends CustomPainter {
  @override
  Future paint(Canvas canvas, Size size) async {
    canvas.save();

    ByteData bd = await rootBundle.load("assets/sampleImagees.jpg");

    final Uint8List bytes = Uint8List.view(bd.buffer);

    final ui.Codec codec = await ui.instantiateImageCodec(bytes);

    final ui.Image image = (await codec.getNextFrame()).image;

    canvas.drawImage(image, Offset(0.0, 0.0), Paint());

    canvas.save();
    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

我的应用没有任何错误,但是什么也没有发生。 它只是一个白屏。我的代码有什么问题呢?
建立的应用程序的白屏:图片链接
2个回答

11

在画布绘制前,需要确保图像已经可用。通过将加载代码移动到绘图器之外,绘图器现在可以按照预期工作:

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  ui.Image _image;

  @override
  void initState() {
    _loadImage();
  }

  _loadImage() async {
    ByteData bd = await rootBundle.load("assets/sampleImagees.jpg");

    final Uint8List bytes = Uint8List.view(bd.buffer);

    final ui.Codec codec = await ui.instantiateImageCodec(bytes);

    final ui.Image image = (await codec.getNextFrame()).image;

    setState(() => _image = image);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(title: Text('Title!')),
      body: Center(
        child: AspectRatio(
          aspectRatio: 1.0,
          child: CustomPaint(
                painter: ImageEditor(_image),
              )
        ),
      ),
    );
  }
}

class ImageEditor extends CustomPainter {
  ui.Image image;

  ImageEditor(this.image) : super();

  @override
  Future paint(Canvas canvas, Size size) async {
    if (image != null) {
      canvas.drawImage(image, Offset(0.0, 0.0), Paint());
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return image != (oldDelegate as ImageEditor).image;
  }
}

请注意,您可以使用Image.asset而不是CustomPainter轻松绘制图像:
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(title: Text('Title!')),
      body: Center(
        child: AspectRatio(
          aspectRatio: 1.0,
          child: Image.asset('assets/sampleImagees.jpg'),
        ),
      ),
    );
  }

太棒了!我尝试了这个方法,它对我有用。但是我遇到了一个问题,就是图像没有被准确地绘制到偏移位置上。你有什么想法吗? - Vishal Parmar
没有更多关于你的代码的信息可能会让我们难以帮助你。我建议你创建一个新的帖子,详细说明你的代码。这样你也会获得更高的曝光率。 - Muldec
感谢您的回复,但现在我已经解决了! - Vishal Parmar

2

正如@Muldec所说,绘制画布之前需要确保图像可用。在这种情况下,适合使用FutureBuilder

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  late Future<ui.Image> _image;

  @override
  void initState() {
    _image = _loadImage('path/image.jpg');
  }

  Future<ui.Image> _loadImage(String imagePath) async {
    ByteData bd = await rootBundle.load(imagePath);
    final Uint8List bytes = Uint8List.view(bd.buffer);
    final ui.Codec codec = await ui.instantiateImageCodec(bytes);
    final ui.Image image = (await codec.getNextFrame()).image;

    return image;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<ui.Image>(
        future: _image,
        builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
          Widget centerChild;
          if (snapshot.hasData) {
            centerChild =
                CustomPaint(painter: ImageEditor(image: snapshot.data!));
          } else {
            centerChild = const CircularProgressIndicator();
          }
          return Scaffold(
              appBar: AppBar(title: const Text('Title!')),
              body: Center(child: centerChild));
        });
  }
}

class ImageEditor extends CustomPainter {
  final ui.Image image;

  ImageEditor({required this.image});

  @override
  Future paint(Canvas canvas, Size size) async {
    canvas.save();

    canvas.drawImage(image, Offset(0.0, 0.0), Paint());

    canvas.save();
    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接