Canvas.drawPaint in Flutter Custom Painter has no boundaries

1.1k Views Asked by At

In the paint method of a CustomPainter, if we use canvas.paint, the paint unexpectedly goes beyond the boundaries of the containing view.

In the example below, I would have expected the pinkAccent of the Container to be visible in the lower half of the column where the text view is... but instead, the green from the adjacent custom painter exceeds the bounds of its Expanded area and paints into the text view's expanded box, and in fact the entire screen.

I would have expected this if the two widgets were part of a stack, but they're in a column.

What changes need to be made to get the expected behavior?

Main:

import 'package:flutter/material.dart';
import 'my_custom_painter.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.pinkAccent,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Expanded(child: CustomPaint(painter: MyCustomPainter(), size: Size.infinite)),
          Expanded(
            child: Container(child: Text("hello")),
          ),
        ],
      ),
    );
  }
}

Custom Painter:

import 'package:flutter/material.dart';

class MyCustomPainter extends CustomPainter {

  Paint boxPaint = Paint();

  @override
  void paint(Canvas canvas, Size size) {

    boxPaint.style = PaintingStyle.stroke;
    boxPaint.strokeWidth = 10;
    boxPaint.color = Colors.black;

    // Unexpectedly paints entire screen, NOT restricted to bounds of this view
    canvas.drawPaint(Paint()..color = Colors.green);
    // Proves that the bounds of this view are correct
    canvas.drawRect(Rect.fromLTRB(0, 0, size.width, size.height), boxPaint);
  }

  @override
  bool shouldRepaint(covariant MyCustomPainter oldDelegate) {
    return true;
  }
}
1

There are 1 best solutions below

0
On

From the CustomPaint documentation:

The painters are expected to paint within a rectangle starting at the origin and encompassing a region of the given size. (If the painters paint outside those bounds, there might be insufficient memory allocated to rasterize the painting commands and the resulting behavior is undefined.) To enforce painting within those bounds, consider wrapping this CustomPaint with a ClipRect widget.