【问题标题】:How can I mask a widget with a png UI image using flutter's custom paint如何使用颤振的自定义绘制用 png UI 图像屏蔽小部件
【发布时间】:2019-09-09 22:05:47
【问题描述】:

我似乎无法用 png ui.Image 掩盖小部件并保持透明度。 透明(不可见)像素被渲染为黑色。

在我的自定义画家上绘制蒙版 png 图像时,我尝试使用 BlendMode srcIn,预期的行为是被果冻豆形状掩盖的彩色背景。 然而,透明(应该删除)像素被渲染为黑色(见附图)。 这是一个错误吗?还是我错过了什么? 我也知道 ImageShader 选项,但它缺乏我在我的应用程序中需要的灵活性。 在屏幕之间转换并应用英雄动画时,画布会按预期呈现。

任何帮助将不胜感激:)

应用屏幕截图

蒙版图片

背景图片

预期

import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:http/http.dart' as http;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ui.Image mask;

  initState() {
    super.initState();

    load('https://img.pngio.com/shape-png-free-download-free-shapes-png-493_315.png')
        .then((image) {
      setState(() {
        mask = image;
      });
    });
  }

  Future<Uint8List> _loadFromUrl(String url) async {
    final response = await http.get(url);

    if (response.statusCode >= 200 && response.statusCode < 300) {
      return response.bodyBytes;
    } else {
      return null;
    }
  }

  Future<ui.Image> load(String asset) async {
    var a = await _loadFromUrl(asset);
    ui.Codec codec = await ui.instantiateImageCodec(a);
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        children: <Widget>[
          Positioned(
            top: 10,
            left: 100,
            child: Hero(
                tag: 'imageHero',
                child: Container(
                  width: 200,
                  height: 200,
                  child: CustomPaint(
                    foregroundPainter: LayerPainter(mask: mask),
                    child: Image.network(
                        "https://www.thecommercialhotel.com/wp-content/uploads/2015/11/Live-Lounge-BG.jpg",
                        fit: BoxFit.fill),
                  ),
                )),
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(context,
              MaterialPageRoute(builder: (BuildContext context) {
            return Page2(mask: mask,);
          }));
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class LayerPainter extends CustomPainter {
  ui.Image mask;

  LayerPainter({@required this.mask}) {}

  @override
  void paint(Canvas canvas, Size size) {
    if (mask != null) {
      canvas.drawImageRect(
          mask,
          Rect.fromLTWH(0, 0, mask.width.toDouble(), mask.height.toDouble()),
          Rect.fromLTWH(0, 0, size.width, size.height),
          new Paint()..blendMode = BlendMode.dstIn);
    }
  }

  @override
  bool shouldRepaint(LayerPainter oldDelegate) {
    return oldDelegate.mask != this.mask;
  }
}

class Page2 extends StatelessWidget {

  final ui.Image mask;

  Page2({ @required this.mask});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Stack(
        children: <Widget>[
          Positioned(
            top: 400,
            left: 100,
            child: Hero(
                tag: 'imageHero',
                child: Container(
                  width: 200,
                  height: 200,
                  child: CustomPaint(
                    foregroundPainter: LayerPainter(mask: mask),
                    child: Image.network(
                        "https://www.thecommercialhotel.com/wp-content/uploads/2015/11/Live-Lounge-BG.jpg",
                        fit: BoxFit.fill),
                  ),
                )),
          )
        ],
      ));
  }
}

【问题讨论】:

    标签: canvas flutter dart mask blend-mode


    【解决方案1】:

    无法解决 Custom Painter 渲染问题,我最终使用了不同的方法。 我只是在单独的画布上渲染蒙版 png,导出 ui.Image 并使用自定义画家绘制它。 Thins 使我能够使用 BlendMode.srcIn 并保持透明度。 您可以在blog post 上阅读更多相关信息

    【讨论】:

    • 您能否添加代码您是如何实现的?谢谢
    • 感谢您的更新和分享博客文章。 @svarog 代码在帖子中。
    • 谢谢,这很有帮助。
    • 域已失效,archive.org 中没有快照。这些信息在其他地方可用吗?
    【解决方案2】:

    不使用自定义painter,使用ShaderMask 和ImageShader 可以获得预期的效果。 This videomy repository 会帮助你。

    【讨论】:

      猜你喜欢
      • 2019-05-10
      • 2020-07-27
      • 2021-08-19
      • 1970-01-01
      • 2020-09-07
      • 2020-05-09
      • 1970-01-01
      • 2018-09-13
      • 1970-01-01
      相关资源
      最近更新 更多