Вырезание отверстия по форме с помощью флаттера

Как мне "вырезать дыру" в форме с помощью флаттера? У меня есть довольно сложный набор форм, которые выглядят как объекты реального мира. У этого объекта есть отверстие в форме прямоугольника со скругленными углами.

Мне бы очень хотелось вычесть RRect из фигуры, но я не могу найти никакой информации о том, как это сделать.canvas.clipRRect(myRRect) просто удаляет все, что не покрыто myRRect, Я хочу противоположность этому. т.е. сделать myRRect Форма отверстия в текущей форме или фигурах холста.

4 ответа

Вы можете использовать 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(),
      ),

  }

}

Результат:

Конечно, если вы хотите, чтобы отверстие было закругленным прямоугольником, просто вычтите RRect вместо 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);

введите описание изображения здесь

Вы можете попробовать другой BlendMode в Custom Painter. Ниже приведен пример, который вы можете использовать:

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 который будет использоваться для отображения источников назначения, но только там, где два источника не перекрываются.

для всех, кто не может заставить работать решение Yann39. Для меня проблема заключалась в том, что я не использовалcanvas.save()в концеpaintметод

Другие вопросы по тегам