我似乎无法用 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),
),
)),
)
],
));
}
}