如何用颤动的画布在形状上“切一个洞”?我有一组相当复杂的形状,看起来像一个真实世界的物体。这个物体上有一个形状像圆角矩形的孔。
我真的很想从一个形状中减去一个 RRect,但我找不到任何关于如何做到这一点的信息。
canvas.clipRRect(myRRect)
只是删除所有未被myRRect
. 我想要相反的。即myRRect
在当前画布形状或形状中制作形状孔。
如何用颤动的画布在形状上“切一个洞”?我有一组相当复杂的形状,看起来像一个真实世界的物体。这个物体上有一个形状像圆角矩形的孔。
我真的很想从一个形状中减去一个 RRect,但我找不到任何关于如何做到这一点的信息。
canvas.clipRRect(myRRect)
只是删除所有未被myRRect
. 我想要相反的。即myRRect
在当前画布形状或形状中制作形状孔。
您可以Path.combine
与difference
操作一起使用来创建孔。
定制画家:
class HolePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint();
paint.color = Colors.blue;
canvas.drawPath(
Path.combine(
PathOperation.difference,
Path()..addRRect(RRect.fromLTRBR(100, 100, 300, 300, Radius.circular(10))),
Path()
..addOval(Rect.fromCircle(center: Offset(200, 200), radius: 50))
..close(),
),
paint,
);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return null;
}
}
用法 :
class EditAvatar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hole in rounded rectangle'),
),
body: CustomPaint(
painter: HolePainter(),
child: Container(),
),
}
}
结果 :
当然,如果您希望孔是圆角矩形,只需减去 aRRect
而不是 a Circle
。
一个解决方案是使用PathFillType.evenOdd
:
// circle with empty RRect inside
final Path path = Path();
path.fillType = PathFillType.evenOdd;
path.addOval(Rect.fromCircle(center: center, radius: radius));
path.addRRect(RRect.fromRectAndRadius(
Rect.fromCircle(center: center, radius: radius / 2),
Radius.circular(radius / 10)));
canvas.drawPath(path, paint);
您可以在 Custom Painter 中尝试使用不同的 BlendMode,以下是您可以参考的示例之一:
class MyPaint extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// below one is big circle and instead of this circle you can draw your shape here.
canvas.drawCircle(Offset(200, 200), 100, Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill);
// below the circle which you want to create a cropping part.
RRect rRect = RRect.fromRectAndRadius(Rect.fromCenter(center: Offset(200, 200), width: 75, height: 75), Radius.circular(8));
canvas.drawRRect(rRect, Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..blendMode = BlendMode.dstOut);
canvas.save();
canvas.restore();
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
在这里,我使用BlendMode.dstOut
which 将用于显示目标源,但仅限于两个源不重叠的地方。